Pytest加-n参数提速的前提是测试无状态,否则会白跑或随机失败;需安装pytest-xdist、避免资源竞争、合理选--dist策略并根据I/O或CPU密集型调整进程数。

直接加 -n 参数就能提速,但多数人卡在“加了没效果”或“加了反而失败”上——根本原因不是参数没写对,而是测试本身没做好并行准备。
为什么 pytest -n 4 有时等于白跑
它不会报错,但实际只跑 1 个进程,或结果随机失败。常见诱因:
-
ImportError: No module named 'xdist':根本没装pytest-xdist,只装了pytest - 加了
-n auto却只启 1 个 worker:os.cpu_count()返回 1(比如 GitHub Actions 默认仅分配 2 核,-n auto就是 1) - 测试里有硬编码端口(如
8000)、固定临时路径(如/tmp/cache.json)、共享数据库连接——多个进程抢同一资源,有的卡住、有的覆盖、有的报PermissionError - 用了
@pytest.fixture(scope='session')但误以为所有 worker 共享一个实例;实际上每个 worker 都会独立执行一次该 fixture
哪些测试必须改才能并行跑
不是所有测试都能直接套 -n。以下几类不改就必出问题:
- 写同一文件:
open('report.txt', 'w')→ 改用tempfile.mkstemp(prefix=f'test_{os.getpid()}_') - 读写同一个 SQLite 文件:
sqlite:///test.db→ 改用sqlite:///file::memory:或带 worker ID 后缀:f"test_{os.environ.get('PYTEST_XDIST_WORKER')}.db" - HTTP 测试绑定固定端口:
HTTPServer(('', 8000), handler)→ 改用HTTPServer(('', 0), handler)让系统自动分配 - 测试类内方法依赖顺序(如
test_login和test_use_token)→ 不能用默认--dist=load,得加--dist=loadgroup并标记:@pytest.mark.xdist_group(name="auth")
--dist 参数选哪个才不踩坑
默认 --dist=load 按单个 test function 分发,最细粒度也最容易撞状态。按场景换策略:
图片提示词生成器?不止如此。 马甲系统 —— 把脑海中的画面,翻译成AI能理解的专业表达。 用得越多,它越懂你:首次需要多问几句确认方向,用久了几乎一说就懂。 用得越多,它越快:缓存机制让后续对话越来越省。 RAG进化:成功案例持续入库,越跑越聪明。 输入「新手指南」查看完整功能介绍
立即学习“Python免费学习笔记(深入)”;
- 测试文件之间完全独立(比如
test_api.py和test_utils.py)→ 用--dist=loadfile - 同一个
class里的多个 test 共享 setup/teardown 或内部状态 → 用--dist=loadscope - 想确保某组标记的测试(如
@pytest.mark.slow)不被拆开 → 用--dist=loadgroup,配合@pytest.mark.xdist_group(name="slow") - CI 环境内存紧张,怕某个 test 占满资源拖垮全部 → 加
--max-worker-restart=2防止单点崩溃雪崩
进程数设多少才真实快
-n auto 是懒人选项,但往往不是最优解:
- I/O 密集型测试(HTTP 请求、DB 查询):
-n 2或-n 4常比-n 8更快,再多进程只是增加上下文切换和锁争抢 - CPU 密集型测试(大量计算、加密解密):可接近物理核数,但别超
os.cpu_count() - 1(留一个核给系统调度) - 混合型测试:先用
pytest --durations=10 -n 4看耗时分布,再决定是否调高或改策略 - Windows 上 spawn 方式启动子进程,若测试 import 了
torch或cv2,可能卡在AttributeError: module '__main__' has no attribute '__file__'→ 改用-n 2或迁移到 Linux CI
真正难的从来不是加参数,而是让每个 test 函数彻底“无状态”:不碰全局变量、不复用连接、不依赖执行顺序、不写死路径或端口。并行不是魔法,它只是把隐式耦合提前暴露出来而已。

















