在 runpy 中使用多处理

Using multiprocessing with runpy

我有一个使用 multiprocessing 的 Python 模块。我正在使用 runpy 从另一个脚本执行此模块。但是,这会导致 (1) 模块 运行ning 两次 ,以及 (2) multiprocessing 作业永远不会完成(脚本只是挂起)。

在我的最小工作示例中,我有一个脚本 runpy_test.py:

import runpy
runpy.run_module('module_test')

和一个包含空 __init__.py[= 的目录 module_test 49=]:

from multiprocessing import Pool

print 'start'
def f(x):
    return x*x
pool = Pool()
result = pool.map(f, [1,2,3])
print 'done'

当我运行runpy_test.py时,我得到:

start
start

然后脚本挂起。

如果我删除 pool.map 调用(或者如果我直接 运行 __main__.py,包括 pool.map 调用) ,我得到:

start
done

我在 运行Scientific Linux 7.6 in Python 2.7.5.

尝试在单独的模块中定义函数 f。它需要被序列化以传递给池进程,然后那些进程需要通过导入它出现的模块来重新创建它。但是,它出现的 __main__.py 文件不是模块,或者在至少,不是一个乖巧的人。尝试导入它会导致创建另一个池和另一个映射调用,这似乎是灾难的根源。

像这样重写你的__main__.py

from multiprocessing import Pool
from .implementation import f

print 'start'
pool = Pool()
result = pool.map(f, [1,2,3])
print 'done'

然后写一个implementation.py(你可以随意调用它),其中定义了你的函数:

def f(x):
    return x*x

否则你会遇到与多处理中的大多数接口相同的问题,并且与使用 runpy 无关。正如@Weeble 解释的那样,当 Pool.map 尝试在每个子进程中加载​​函数 f 时,它将导入 <your_package>.__main__ 定义函数的位置,但是由于您在模块级别具有可执行代码在__main__中,它会被子进程重新执行。

抛开这个技术原因,这在关注点分离和测试方面也是更好的设计。现在您可以轻松导入和调用(包括用于测试目的)函数 f 而无需并行 运行 它。

虽然不是 "right" 的方法,但最终对我有用的一种解决方案是使用 runpy 的 _run_module_as_main 而不是 run_module。这对我来说非常理想,因为我正在使用其他人的代码并且需要最少的更改。