如何在Windows系统下使setup.py test与multiprocessing正常兼容?
这个问题我太熟悉了!Windows系统的multiprocessing机制和setuptools的test命令天生有点“不对付”,我来给你几个实用的解决办法:
方法1:在测试代码中显式调用freeze_support()
Windows下multiprocessing要求在主进程的主模块入口调用freeze_support(),否则会触发那个烦人的RuntimeError。你可以在测试文件的最顶部加上这段代码:
import multiprocessing # 确保只在主进程执行时调用 if __name__ == '__main__': multiprocessing.freeze_support()
如果遇到setup.py test执行时测试模块__name__不是__main__的情况,也可以把逻辑放到测试类的setUpClass方法里(确保只执行一次):
import multiprocessing import unittest class MyTestCase(unittest.TestCase): @classmethod def setUpClass(cls): multiprocessing.freeze_support() # 其他初始化逻辑...
方法2:自定义setup.py的test命令(最稳妥)
setuptools原生的test命令没处理Windows的multiprocessing场景,我们可以自己写一个test命令,先调用freeze_support()再执行测试。修改你的setup.py:
from setuptools import setup, Command import multiprocessing import unittest class CustomTestCommand(Command): user_options = [] def initialize_options(self): pass def finalize_options(self): pass def run(self): # 先处理Windows的multiprocessing需求 multiprocessing.freeze_support() # 用unittest自动发现并运行测试 test_loader = unittest.TestLoader() test_suite = test_loader.discover('tests', pattern='test_*.py') unittest.TextTestRunner(verbosity=2).run(test_suite) setup( # 你的项目名称、版本等原有配置... name="your-package-name", version="0.1.0", # 替换默认的test命令为我们自定义的 cmdclass={'test': CustomTestCommand}, )
之后再运行python setup.py test,就不会再触发freeze_support的错误了。
方法3:改用更现代的测试方式(推荐长期方案)
其实setuptools的test命令已经被官方废弃了(从setuptools 40.0.0版本开始),官方更推荐直接用python -m unittest或者集成pytest:
- 如果你想保留setup.py的调用方式,可以添加
pytest-runner依赖,然后在setup.py里配置:
setup( # 其他配置... tests_require=["pytest"], setup_requires=["pytest-runner"], )
之后运行python setup.py pytest就能执行测试,pytest会自动处理Windows下multiprocessing的兼容性问题。
为什么会出现这个问题?
简单说:Windows下multiprocessing用的是spawn模式创建子进程,这种模式会重新导入主模块。如果没有if __name__ == '__main__'的保护或者没有提前调用freeze_support(),就会导致子进程启动时重复执行初始化代码,触发错误。而setup.py test的执行流程和直接运行python -m unittest不同,导致freeze_support()没有被正确触发。
内容的提问来源于stack exchange,提问作者NOhs

