我正在尝试并行化脚本,但由于未知原因,内核只是冻结而没有抛出任何错误。
最小工作示例:
from multiprocessing import Pool
def f(x):
return x*x
p = Pool(6)
print(p.map(f, range(10)))
有趣的是,如果我在另一个文件中定义我的函数然后导入它,一切正常。如何在不需要其他文件的情况下使其工作?
我使用 spyder(anaconda(,如果我从 windows 命令行运行我的代码,我会得到相同的结果。
发生这种情况是因为在子进程导入f
时,您没有保护代码的"过程"部分不被重新执行。
他们需要导入f
,因为Windows不支持分叉作为新进程的启动方法(仅生成(。一个新的 Python 进程必须从头开始,f
导入,此导入还将触发在所有子进程中创建另一个池......以及他们的子进程和他们的子进程...
为了防止这种递归,您必须在上半部分和下半部分之间插入一行if __name__ == '__main__':
行,前者应在导入时运行,后者应仅在脚本作为主脚本执行时运行(仅父脚本的情况(。
from multiprocessing import Pool
def f(x):
return x*x
if __name__ == '__main__': # protect your program's entry point
p = Pool(6)
print(p.map(f, range(10)))
像这样分离你的代码对于Windows和Unix-y系统上的多处理是强制性的,当与"spawn"或"forkserver"启动方法而不是默认的"fork"一起使用时。通常,可以使用multiprocessing.set_start_method(method)
修改启动方法。
从Python 3.8开始,macOS也默认使用"spawn"而不是"fork"。
通常,将上层">定义"和下层"作为主执行"中的任何脚本分开是一种很好的做法,以使代码可导入,而不会不必要地执行仅在作为顶级脚本运行时相关的部分。最后但并非最不重要的一点是,当您不混合定义和执行时,它有助于理解程序的控制流。