如何让 `setup.py test` 在 Windows 上与 `multiprocessing` 一起工作?

How to get `setup.py test` working with `multiprocessing` on Windows?

问题

我正在尝试让 setup.py test 使用在 Windows 上使用多处理的包。我有以下情况:

运行

python -m unittest

从顶级目录执行我的测试没有抱怨。然而,当调用

python setup.py test

我遇到了众所周知的 freeze_support 问题(请参阅此处的几个问题):

RuntimeError: 
    An attempt has been made to start a new process before the
    current process has finished its bootstrapping phase.
    This probably means that you are not using fork to start your
    child processes and you have forgotten to use the proper idiom
    in the main module:
        if __name__ == '__main__':
            freeze_support()
            ...
    The "freeze_support()" line can be omitted if the program
    is not going to be frozen to produce an executable.

但是,以下 where to put freeze_support() in a Python script? 实际上,我的所有文件中都有所描述的保护措施,可能太多了。

问题 1:为了 setup.py test 我的项目需要更改什么才能使用我的多处理函数?

问题2:我放置的freeze_support()中哪些是实际需要的?据我所知,这通常只在编译冻结的可执行文件时才需要。

MWE

文件夹结构

project
│   setup.py
│
└─── my_package
│    │   __init__.py
│    │   my_package.py
│   
└─── test
│    │   __init__.py
│    │   test_it.py

__init__.py个文件是空的,其他的是:

my_package.py

import multiprocessing

def say_hi(arg):
    print('hi')

def main():
    pool = multiprocessing.Pool(1)
    pool.map(say_hi, range(1))

if __name__ == '__main__':
    multiprocessing.freeze_support()
    main()

test_it.py

import multiprocessing
import unittest

from my_package import my_package

class TestIt(unittest.TestCase):
    def test_say_hi(self):
        my_package.main()

if __name__ == '__main__':
    multiprocessing.freeze_support()

setup.py

#!/usr/bin/env python

import setuptools
import multiprocessing

setuptools.setup(
    name = "my_package"
)

if __name__ == '__main__':
    multiprocessing.freeze_support()

我遇到了类似的问题。 我发现当通过 setup.py 执行测试时,由 multiprocessing 创建的新进程调用 setuptools.setup 方法,这会影响一些事情。 (我不清楚根本原因...)

就我而言,setup.py 解决了这个问题。

#!/usr/bin/env python

import setuptools

if __name__ == '__main__':
    setuptools.setup(
        name = "my_package",
        ....,
    )

如前所述,我认为此程序运行if setuptools.setup仅在__name__ == 'main'成立时执行。

根本原因

当您使用多处理生成进程时,将导入模块,将 __name__ 属性设置为“__mp_main__”(不是 __main__)。

这是 _fixup_main_from_pathmultiprocessing.spawn.py

的代码片段
# If the parent process has sent a path through rather than a module
# name we assume it is an executable script that may contain
# non-main code that needs to be executed
old_main_modules.append(current_main)
main_module = types.ModuleType("__mp_main__")
main_content = runpy.run_path(main_path,
                              run_name="__mp_main__")
main_module.__dict__.update(main_content)
sys.modules['__main__'] = sys.modules['__mp_main__'] = main_module

因此,如果setuptools.setup在模块顶层执行,就会出现无限递归。