我正在尝试运行在web中找到的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笔记本的内核.有什么问题?
正如您可能从评论中指出的答案中读到的那样multiprocessing.Pool
,一般来说,不应期望在交互式解释器中工作得很好.要理解为什么会这样,考虑Pool
它的工作原理:
它分叉python worker,向他们传递当前Python文件的名称.
然后工人基本上做import
,并听取主人的消息.
主机通过酸洗将函数名称和函数参数一起发送给工人.请注意,函数本身无法发送,因为pickle协议不允许这样做.
当您尝试从交互式提示中执行此过程时,没有合理的"当前Python文件"传递给子项以进行导入.此外,您在交互式提示中定义的函数不是任何模块的一部分(它们是动态定义的),因此子项不能从该不存在的模块中导入.因此,最简单的方法就是避免multiprocessing
在IPython中使用.无论如何,IPython并行更好:)
为了完整起见,我还检查了在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
.第488行multiprocessing/forking.py
说:
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
内置函数.如果您要求工作人员计算您在笔记本中定义的函数,它将失败(优雅地,例外).
事实证明,原则上你可以进一步处理黑客行为,并使用他们的代码手动腌制将你的功能发送给工人.你可以找到这样一个黑客的一个很酷的例子在这里.