pytest并行测试插件
项目描述
pytest-freethreaded
一个Pytest插件,用于帮助验证您的测试和库是否在Python 3.13实验性的freethreaded
模式下线程安全。
为什么我需要这个插件?
Python 3.13引入了一种新模式,称为freethreaded
,允许您在没有全局解释器锁(GIL)的情况下运行Python代码。这对于并行运行CPU密集型代码很有用,但也意味着您的代码必须是线程安全的。
一些具有良好、成熟的测试基础的包和库已将其库标记为与freethreaded
兼容,但它们只运行了一次测试,并且是在单线程中!
Pytest-xdist无法帮助您,因为它使用多进程来并行化测试,并且GIL仍然处于启用状态。
因此,我们制作了这个插件,以帮助您在没有GIL的线程池中运行测试,以帮助您确定您的测试是否是线程安全的。
我们在第一个测试库上进行了测试(标记为兼容),在CPython中导致了段错误!因此,如果您是包维护者,您应该尝试一下。
安装
pip install pytest-freethreaded
用法
我们建议分阶段使用此插件来识别您的测试是否可以在禁用 GIL 的线程池中运行,然后再禁用 GIL。
第一阶段:您的测试应该在没有此插件的情况下通过
首先,您的测试应该正在运行,并且您应该有测试。
第二阶段:在启用 GIL 的情况下运行您的测试,但具有并发性
此插件将并行运行多次。默认情况下,它将执行每个测试 10 次,然后重复 20 次。这意味着每个测试将运行 200 次。这很多,所以我们建议只运行此循环一次,或者在一个测试子集上。
如果在任何运行中测试失败,我们将引发一个特殊的错误,称为 ConcurrencyError
,它表示测试部分失败,很可能是由于线程不安全性和/或竞态条件。
选择特定测试
如果在第一阶段您决定只运行测试子集,您可以使用 -k
标志通过名称选择测试。
或者,您可以使用标记设置线程数和执行次数
import pytest
@pytest.mark.freethreaded(threads=10, executions=10)
def test_my_threaded_code():
pass
然后在命令行中将线程数和执行次数设置为 1
pytest --threads 1 --executions 1
第三阶段:禁用 GIL 运行您的测试
如果您通过了第三阶段;恭喜!您现在可以禁用 GIL 运行测试。
我们建议在此阶段使用 Pytest 的 --require-gil-disabled
标志,这样如果意外使用带 GIL 的 Python 3.13 运行,测试将失败。
pytest --require-gil-disabled
在此最终阶段,如果您看到任何 新 的并发错误,甚至在 Python 3.13 中看到崩溃,您将需要调试它。
开发
设置
python3.13t -m venv .venv
source .venv/bin/activate
python -m pip install flit
python -m flit install -s
测试
运行测试
pytest -vvvv --log-level=DEBUG
鸣谢
此扩展是在 PyCon JP 奔跑中创建的,以下团队成员参与其中
- Anthony Shaw @tonybaloney
- Mike Hommey @glandium
- Oliver Basset @obassett
- Maryanne Wachter @m-clare
- Toshihiko Yanase @toshihikoyanase
- Heejun Shin @abel9851
- Otake Katsuaki
- Rei Suyama @rhoboro