Python多处理池卡住了

时间:2015-12-04 10:24:55

标签: python threadpool ipython-notebook python-multiprocessing

我试图运行一些python的multiprocessing.pool模块的示例代码,可以在网上找到。代码是:

def square(x):
    return x * x
if __name__ == '__main__':
    pool = Pool(processes=4)
    inputs = [0, 1, 2, 3, 4]
    outputs = pool.map(square, inputs)

但是当我尝试运行它时,它永远不会完成执行,我必须重新启动我的IpythonNotebook笔记本的内核。 问题是什么?

1 个答案:

答案 0 :(得分:8)

正如您在评论中所指出的the answer所述,multiprocessing.Pool一般来说,不应期望在交互式口译员中工作得很好。要理解为什么会这样,请考虑Pool如何完成其​​工作:

  • 它派遣python worker,向他们传递当前Python文件的名称。
  • 然后工人基本上做import <this file>,并听取来自主人的信息。
  • 主机通过酸洗将函数名称和函数参数一起发送给工人。请注意,函数本身无法发送,因为pickle协议不允许这样做。

当您尝试从交互式提示中执行此过程时,没有合理的“当前Python文件”传递给子项以进行导入。此外,您在交互式提示中定义的函数不是任何模块的一部分(它们是动态定义的),因此子项不能从该不存在的模块中导入。因此,最简单的方法是避免在IPython中使用multiprocessingIPython parallel无论如何都要好得多:)

为了完整起见,我还检查了在Windows 8上运行在Python 2.7下的IPython 4的特定情况下究竟发生了什么(我可以观察到解释器也被卡住了)。有趣的是,IPython首先陷入困境的原因并不是上面提到的那个。

事实证明,多处理检查是否定义了__main__.__file__,如果没有,则将sys.argv[0]作为“当前文件名”发送给孩子。在(我的版本)IPython sys.argv[0]等于C:\Dev\Anaconda\lib\site-packages\ipykernel\__main__.py的情况下。

不幸的是,工作流程在启动之前会检查他们要导入的文件是否已经在他们的sys.modules中。 multiprocessing/forking.py的第488行说:

assert main_name not in sys.modules, main_name

main_name__main__时(与ipython的工作人员一样),此断言失败,工作人员无法启动。但是,相同的代码足够“智能”来检查传递的名称是否为ipython,在这种情况下,它不执行此类检查,也不会导入任何内容。

因此,使用将__main__.__file__定义为ipython的丑陋黑客可以解决工人未能启动的问题。以下代码可以在IPython单元格中正常工作:

import sys
sys.modules['__main__'].__file__ = 'ipython'
from multiprocessing import Pool

pool = Pool(processes=4)
inputs = [0, 1, 2, 3, 4]
outputs = pool.map(abs, inputs)

请注意,此示例要求工作人员计算内置函数abs。如果您要求工作人员计算您在笔记本中定义的函数,它将失败(优雅地,例外)。

事实证明,原则上你可以进一步处理黑客行为,并使用他们的代码手动腌制将你的功能发送给工人。你可以找到一个非常酷的例子来解决这个问题here