装 10 个包实测 uv:比 pip 快 3.8 倍,但别信 100 倍
装 10 个包实测 uv:比 pip 快 3.8 倍,但别信 100 倍
Python 装包这件事,十几年没怎么变过:pip 串行下载、串行解包、装完给你一串黄色警告。uv 是 Astral(Ruff 的作者)用 Rust 重写的一套东西,同一个可执行文件里塞了虚拟环境、依赖解析、锁文件、解释器版本管理,宣称比 pip 快 10 到 100 倍。
「快 10 到 100 倍」这种话,跑一次就知道水分在哪。我这次只做一件事:在干净目录里,用同一批包、同一个镜像源,让 uv 和 pip 各装一遍,把墙钟时间记下来。下面所有数字都是本机单次实测,命令和输出原样贴出,路径里的个人目录用 <工作目录> 代替。
装:一条命令,11.19 秒
pip install uv -i https://pypi.tuna.tsinghua.edu.cn/simple
# Looking in indexes: https://pypi.tuna.tsinghua.edu.cn/simple
# Collecting uv
# Downloading .../uv-0.13.1-py3-none-win_amd64.whl (15.4 MB)
# ---------------------------------------- 15.4/15.4 MB 56.8 MB/s 0:00:00
# Installing collected packages: uv
# Successfully installed uv-0.13.1
墙钟 11.19 秒,退出码 0。这里必须说明一件事:我一开始没加镜像,直接 pip install uv,光解析就花了 18.47 秒,然后卡在下载上,60 秒时被我手动掐掉(退出码 124)。换国内镜像后同一个包 11 秒装完。所以这 11 秒里,网络占比不小,工具本身解压安装只占末尾一小段。
装完查版本:
uv --version
# uv 0.13.1 (62faed335 2026-10-13 x86_64-pc-windows-msvc)
落地的 uv.exe 是 32,095,024 字节,约 30.6MB。它是静态链接的 Rust 二进制,uv --version、uv venv 这类命令不需要本机有 Python 参与,只有真要执行代码时才去找解释器——这点对基础镜像很有用,镜像里可以先不放 Python。
建环境:它没听我的
uv venv .venv
# Using CPython 3.13.13
# Creating virtual environment at: .venv
# Activate with: .venv\Scripts\activate
我系统里 python --version 是 3.14.3,uv 却挑了 3.13.13——它优先用了自己管理的那份解释器(uv python list --only-installed 能看到本机已有多份,包括 uv 自己下过的 3.13 和 3.12)。这个行为值得留意:你以为在用系统 Python,实际不是。要钉死版本就显式指定 uv venv --python 3.14。
建环境这一步没有多余的输出,退出码 0,Activate with: 一行直接把激活命令给全了,不用背平台差异。
同条件对照:9.93 秒 对 38.16 秒
条件:同一台机器、同一个清华镜像、同样三个包(numpy、requests、pandas)加 7 个传递依赖,各自全新的虚拟环境,两边缓存都是冷的。
uv 侧:
uv pip install numpy requests pandas
# Resolved 10 packages in 1.11s
# Downloading numpy (12.0MiB)
# Downloading pandas (9.2MiB)
# Downloaded numpy
# Downloaded pandas
# Prepared 10 packages in 6.35s
# Installed 10 packages in 1.88s
# + certifi==2026.7.22
# + charset-normalizer==3.5.2
# + idna==3.20
# + numpy==2.5.4
# + pandas==3.0.6
# + python-dateutil==2.9.0.post0
# + requests==2.34.2
# + six==1.17.0
# + tzdata==2026.5
# + urllib3==2.8.0
墙钟 9.93 秒。它自己拆了账:解析 1.11 秒、准备(下载+解包)6.35 秒、装进环境 1.88 秒。三个阶段的耗时加起来 9.34 秒,和墙钟基本对得上,说明它确实是并行干的。
pip 侧:
python -m venv .venv2
.venv2\Scripts\python.exe -m pip install numpy requests pandas -i https://pypi.tuna.tsinghua.edu.cn/simple
# Successfully installed certifi-2026.7.22 charset_normalizer-3.5.2 idna-3.20
# numpy-2.5.4 pandas-3.0.6 python-dateutil-2.9.0.post0 requests-2.34.2
# six-1.17.0 tzdata-2026.5 urllib3-2.8.0
墙钟 38.16 秒。同样的 10 个包、同样的版本号、同一个源。
| 场景 | uv | pip | 倍数 |
|---|---|---|---|
| 冷缓存装 10 个包 | 9.93s | 38.16s | 3.8× |
| 热缓存装 10 个包 | 1.41s | 37.23s | 26× |
| 完全禁用缓存 | 30.29s | 45.08s | 1.5× |
装完验证能用:
uv run python -c "import numpy, pandas; print(numpy.__version__, pandas.__version__)"
# 2.5.4 3.0.6
热缓存与那个「100 倍」
热缓存场景我特意测了,因为宣传数字基本都从这里来。删掉环境重建,再装同一批包:
uv venv .venv_warm
uv pip install --python .venv_warm/Scripts/python.exe numpy requests pandas
# + six==1.17.0
# + tzdata==2026.5
# + urllib3==2.8.0
墙钟 1.41 秒。pip 那边同样缓存已热的第二次安装是 37.23 秒——几乎和第一次一样,因为 pip 的瓶颈不在下载,在逐个包解包、写元数据、跑一遍安装钩子,10 个包每个三秒多。
1.41 秒对 37.23 秒是 26 倍,比宣传的 100 倍保守,但方向一致。
真正有意思的是第三组:把 uv 的缓存彻底关掉(--no-cache),它变成 30.29 秒。也就是说,uv 那 3.8 倍的优势里,一大半来自缓存和硬链接复用,纯下载解包只比 pip 快一点。这个结论对选型有实际意义:如果你的 CI 每次都是全新容器、缓存挂不上,别指望 3.8 倍,能拿到 1.3 到 1.5 倍就不错。
项目式工作流:从 init 到 run
uv pip 只是兼容 pip 的那一层,uv 真正的定位是项目管理器。uv --help 一共列了 23 个子命令,从 auth、init、add 一直排到 workspace、cache、self,pip 那条路只是其中一格。
uv init demo-project
# Initialized project `demo-project` at `<工作目录>\demo-project`
一条命令生成的东西比想象中多:pyproject.toml、README.md、.python-version、.gitignore、src/demo_project/__init__.py,顺手还 git init 了一个仓库。构建后端默认是 uv_build,不是 setuptools。
加依赖、同步、看树:
uv add httpx
# Resolved 8 packages in 781ms
# Prepared 6 packages in 387ms
# Installed 8 packages in 159ms
# + httpx==0.28.1
墙钟 1.91 秒,其中包括建虚拟环境、解析、装 8 个包、写 uv.lock(5580 字节)。
uv sync
# Resolved 8 packages in 1ms
# Checked 8 packages in 1ms
uv tree
# demo-project v0.1.0
# └── httpx v0.28.1
# ├── anyio v4.15.1
# │ ├── idna v3.20
# │ └── typing-extensions v4.16.0
# ├── certifi v2026.7.22
# ├── httpcore v1.0.9
# │ ├── certifi v2026.7.22
# │ └── h11 v0.16.0
# └── idna v3.20
uv sync 两个阶段都是 1 毫秒级——锁文件和环境一致时它什么都不做,这个反馈很干脆。
跑项目入口:
uv run demo-project
# Hello from demo-project!
这里我踩了个坑,照实记一下。我下意识敲了 uv run main.py,因为印象里 uv init 会在项目根目录留一个 main.py:
uv run main.py
# error: Failed to spawn: main.py
# cause: program not found
# 退出码 2
这个版本生成的是 src 布局,根目录没有 main.py,入口写在 pyproject.toml 的 [project.scripts] 里,对应的源码是 src/demo_project/__init__.py。报错信息很直接,但如果你照着旧教程敲 main.py,就会在这里卡一下。我没有回退到旧版本去对比目录结构,所以「哪个版本改的」这一点我不下结论。
单文件的内联依赖是我最喜欢的一处。不用建环境、不用 requirements.txt,把依赖写在文件头的注释块里:
# /// script
# requires-python = ">=3.12"
# dependencies = ["httpx==0.28.1"]
# ///
import httpx
print("httpx", httpx.__version__)
uv run demo_script.py
# Installed 7 packages in 341ms
# httpx 0.28.1
墙钟 4.54 秒,从零建环境到跑出结果。这种「发一个文件给别人,他那边直接能跑」的形态,比附带 requirements 的压缩包省事得多。
这次没有验证的部分
先把话说清楚:上面所有数字都来自一台 Windows 10 机器、单次测量、没取均值。
验证过的:pip install uv 安装、版本号、uv venv 建环境、uv pip install 冷/热/禁缓存三种装包耗时、pip 侧同条件对照、uv init/add/sync/tree/run 全流程、单文件内联依赖、以及 uv run main.py 的失败路径。
没验证的,按重要性排:
- 大型依赖树。我只测了 10 个包。uv 的并行优势在 100 个包以上才真正显形,但没有实测数据,我不替它下结论。
- CI 场景。缓存能不能挂、挂上之后命中率多少,取决于具体流水线配置,这台机器上无法复现。
- 跨平台一致性。
uv.lock号称跨平台,我只在 Windows 上生成过,没在 Linux/macOS 上验证同一个锁文件能否装出一样的结果。 uv python install下载解释器。本机已经有 uv 管理的 3.13 和 3.12,这一步没触发下载,所以「自动装 Python」的能力我其实没测到。- 私有源、代理、企业证书。全部用的公网镜像,没碰这些坑。
uv build/uv publish。完全没试。
还有一个方法论上的坑要提醒:pip 和 uv 的耗时都受网络影响很大,我这边第一次直连 PyPI 时 60 秒都没下完。所以绝对值换台机器就会变,比例比绝对值更可信。
实测边界声明
本文所有命令均在 Windows 10 (19045) 执行:系统 Python 3.14.3,uv 自己挑的解释器是 3.13.13,uv 版本 0.13.1(commit 62faed335)。数据为单次墙钟测量,未重复取样,误差估计 ±1 秒。包下载走清华镜像,直连 PyPI 在本机不可用,故所有耗时均含镜像网络时间。pip 侧对照使用相同镜像、相同包集合、全新虚拟环境,缓存目录为新建,视为冷缓存。输出中的个人目录路径已替换为 <工作目录> 占位符,其余内容未改动。
项目链接与许可证
- 仓库:https://github.com/astral-sh/uv
- 文档:https://docs.astral.sh/uv/
- 许可证:MIT 与 Apache-2.0 双许可(仓库内同时存在
LICENSE-MIT与LICENSE-APACHE两个文件,可按需二选一) - 本次实测版本:0.13.1
- 点赞
- 收藏
- 关注作者
评论(0)