pixi cookbook
Conda的前世今生
在介绍pixi之前,有必要先聊聊Conda。实际上Conda最早诞生于2012年,晚于pip和venv,为什么在已经存在pip和venv的情况下,还要推出一个看似重复的包管理工具呢?
将时间倒回2012年,python的包管理面临着一个巨大的问题。彼时,很多科学计算库(如 NumPy, SciPy, Pandas)底层都是用 C、C++ 或 Fortran 编写的,而 pip 主要安装的是源码包(sdist)。这意味着当你执行pip install numpy时,你的电脑必须装有对应的编译器、动态链接库和复杂的数学库(如 MKL 或 OpenBLAS)。如果环境不匹配,安装就会报错。这是一个让人头疼的事情(尤其是那些编程基础本就不扎实的科学家们)。
当时 Anaconda 的创始人 Travis Oliphant 意识到,科学计算的用户(物理学家、生物学家、金融分析师)不应该把时间花在解决 gcc 编译器报错上。因此,Conda出现了,它直接分发预编译好的二进制文件。这就意味着用户不需要在本地编译,直接下载解压就能用。由于不需要处理那些烦人的依赖,这对很多那些科学家来说简直是救命稻草。而将所有这些库以及非python编写的依赖库打包在一起的巨大的库,就是 Anaconda Distribution。如今,它是目前全球最流行的科学计算平台,本质上是将 Python、Conda 包管理器以及一大堆常用的科学计算库打包在一起的软件发行版。
不过在最初,Anaconda Distribution只是一个将所有软件包放在一起的大杂烩,在后续的更新中,人们意识到需要一个类似于 pip 的命令来管理这些依赖库,比如添加、更新和删除依赖,于是,conda命令行诞生了。他们维护的那个软件包仓库,在当时叫做default。
在一段时间以来,他们维护着官方的 defaults ,这是一个经过严格测试的软件包仓库,兼容性极好。但问题也随之而来:科学计算的世界太大了。除了 NumPy、Pandas 这些通用的,还有成千上万个小众领域的库(比如天文学的 Astropy、地理信息的 GDAL、生物信息学的Biopython)。这对于一家商业公司(当时甚至只是个创业公司)来说,根本没有人力去打包、编译、测试全世界所有的科学软件。而且,Conda 包是二进制文件,需要针对 Windows、Linux、macOS 分别编译,工作量是 PyPI 的数倍。
为了解决这个问题,Anaconda开放了 Channel 机制。 他们推出了 Anaconda.org(最初叫 Binstar.org),允许用户创建自己的 Channel。如果你需要的包官方不提供,那么你可以自己打包上传到你的个人频道,别人只要添加你的 URL 就能下载。
将权限下放给用户,解决了官方维护成本的问题,但是随着个人 Channel 的开放,又带来了过于混乱的问题。很快,大家就发现,如果要装 tensorflow,在搜索时可能会发现:
google/tensorflowzhang3/tensorflowalice/tensorflow
如此多的tensorflow,你敢用吗?这些包是基于什么环境编译的?有没有植入恶意代码?彼此兼容吗?一群核心开发者意识到,不能让成千上万个个人频道各自为战。于是他们建立了一个社区驱动的超级频道 —— conda-forge。它引入了自动化的 CI/CD 流水线。任何人都可以在 GitHub 上提交 Recipe,由CI自动构建,并由社区审核。它解决了信任和标准化的问题,成为了现如今的事实标准。
而对于那些生物信息学的软件。很多底层工具是用 Perl、C++ 甚至 Fortran 写的老古董,而且依赖关系极其复杂(不仅仅依赖 Python,还依赖系统级的库)。这些软件对于做金融或做 Web 开发的人来说完全没有用,拖慢搜索速度。而且,生物软件的版本更新逻辑和通用软件完全不同。因此,Bioconda Channel 诞生了。 这是一群生物学家建立的。他们把所有生物相关的软件(超过 7000 个)都放在这个频道里。通过 Channel,不同领域的人可以在自己的圈子里维护自己的生态,互不干扰。
pixi:新时代的包管理方案
既然 Conda 生态已经如此成熟,为什么还需要 pixi?
简单来说,pixi 是一个基于 Rust 编写(底层使用 rattler 库)、强调完全可重现性和极高性能的现代化包管理器。它不仅完全兼容 Conda 庞大的 conda-forge 生态,还通过内置的 uv 库实现了对 PyPI 的“一等公民”级支持。
相比于传统的 Conda 客户端,pixi 的核心优势在于:
- 快到极致:依赖解析速度比传统 conda 快几个数量级。
- 声明式配置:不再依赖一系列手动输入的命令行指令,所有配置都记录在一个
pixi.toml中。 - 强制锁文件:生成
pixi.lock确保跨平台、跨机器的安装结果 100% 一致。 - 无需激活:直接运行
pixi run即可,不再需要繁琐的conda activate。
快速上手
对于 Python 项目,pixi 推荐直接使用 pyproject.toml 作为配置文件。这不仅符合 Python 社区的标准,还能让你在同一个文件中管理构建系统、项目元数据以及 pixi 专有的环境配置。
1. 安装 pixi
在 macOS 或 Linux 上,使用官方脚本进行一键安装:
1 | curl -fsSL https://pixi.sh/install.sh | sh |
安装脚本会将 ~/.pixi/bin 添加到 PATH。安装完成后,重启终端以使配置生效。
2. 初始化项目(pyproject.toml 模式)
进入你的项目目录,使用 --format pyproject 参数初始化:
1 | pixi init my-project --format pyproject |
此时生成的 pyproject.toml 会包含 [tool.pixi.workspace] 部分。pixi 会自动将 requires-python 映射为 Python 依赖,并将当前项目以可编辑模式(editable)添加到环境中。
3. 添加依赖(Conda 与 PyPI 混合)
pixi 遵循 “Conda 优先” 策略:先解析 Conda 依赖,再处理 PyPI 依赖。
1 | # 添加 Conda 依赖(存放在 [tool.pixi.dependencies]) |
执行后,pixi 会更新 pyproject.toml 并同步生成 pixi.lock 文件。该锁文件记录了跨平台一致的精确依赖版本。
4. 运行代码
在 pixi 中,你不需要手动激活环境。通过 pixi run 执行命令时,pixi 会自动确保环境处于最新状态。
直接运行 Python 命令:
1 | pixi run python -c "import rich; rich.print('[bold magenta]Hello Pixi![/bold magenta]')" |
如果需要交互式 Shell,可以使用:
1 | pixi shell |
5. 查看环境状态
1 | # 列出当前环境的所有包及其来源(Conda 或 PyPI) |
进阶配置
1. 任务管理 (Tasks)
pixi 允许你在 pyproject.toml 中定义跨平台的任务命令,类似于 npm scripts。
在 [tool.pixi.tasks] 区域添加定义:
1 | [tool.pixi.tasks] |
使用方式:
1 | pixi run start |
2. 多环境管理 (Features & Environments)
这是 pixi 最强大的特性之一。你可以为测试、生产或文档生成定义不同的环境,而它们共享同一个锁文件。
pixi 会自动将 [project.optional-dependencies] 或 [dependency-groups] 识别为“特性 (Features)”:
1 | [dependency-groups] |
- solve-group: 将多个环境放入同一个 solve-group,可以确保它们安装的共同依赖版本完全一致,避免环境切换时的包冲突。
3. 系统需求 (System Requirements)
如果你的项目依赖特定的硬件环境(如 GPU)或系统库,可以通过 system-requirements 告知 pixi,它会在解析依赖时进行校验。
1 | [tool.pixi.system-requirements] |
深度解析:Conda Channels 与 PyPI 集成
Pixi 的核心灵魂在于它如何协调 Conda 庞大的多语言二进制生态与 PyPI 极速更新的 Python 生态。
1. Conda Channels
在 Pixi 中,Channel 是获取二进制包的路径。默认情况下,Pixi 仅使用 conda-forge,这保证了环境的纯净和高度兼容。
- 添加自定义频道:如果需要特定领域的包(如高性能计算或生物信息学),可以在
[tool.pixi.workspace]中配置:1
2[tool.pixi.workspace]
channels = ["pytorch", "nvidia", "conda-forge"] - 优先级规则:Pixi 遵循严格的顺序优先级。在上面的配置中,如果
pytorch和conda-forge都有同名的包,Pixi 会优先从pytorch下载。 - 镜像源配置:为了加速国内访问,可以在项目根目录或全局配置(
~/.pixi/config.toml)中设置mirrors,但这通常是针对特定域名的重定向。
2. PyPI 集成
虽然 Pixi 诞生于 Conda 社区,但它通过内置 uv 引擎,将 PyPI 支持做到了极致。
- 配置位置:
[project.dependencies]:标准的 Python 项目依赖,会被uv解析。[tool.pixi.pypi-dependencies]:如果你不使用pyproject.toml格式,或者想在特定的 Pixi 环境中添加 PyPI 包。
- 高级依赖类型:Pixi 支持所有现代
pip支持的安装方式:1
2
3
4
5
6
7[tool.pixi.pypi-dependencies]
# 1. 直接从 Git 仓库安装
requests = { git = "https://github.com/psf/requests.git", branch = "main" }
# 2. 从特定 URL 安装
torch = { url = "https://download.pytorch.org/whl/cpu/torch-2.0.1%2Bcpu-cp310-cp310-linux_x86_64.whl" }
# 3. 本地路径(常用于单体仓库中的模块)
my-common-lib = { path = "../libs/common" }
3. 最佳实践
Pixi 的解析逻辑是:先 Conda,后 PyPI。
- 解决冲突:如果一个包(如
numpy)同时出现在 Conda 依赖和 PyPI 依赖中,Pixi 会强制选择 Conda 版本,并告诉uv忽略 PyPI 上的对应包。这是为了利用 Conda 优化的二进制加速(如 MKL)。 - 何时用 PyPI?:
- 当
conda-forge还没有收录某个新包时。 - 当某个包的 Conda 版本更新极其缓慢时。
- 纯 Python 的小型库。
- 当
- 环境稳定性:建议尽可能将核心科学计算库(NumPy, SciPy, PyTorch)放在 Conda 中,而将 Web 框架、辅助工具放在 PyPI 中。