跳转到主要内容

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

由以下支持

AWS AWS 云计算和安全赞助商 Datadog Datadog 监控 Fastly Fastly CDN Google Google 下载分析 Microsoft Microsoft PSF赞助商 Pingdom Pingdom 监控 Sentry Sentry 错误记录 StatusPage StatusPage 状态页面