使用joblib.Parallel时,为什么保护主循环很重要?

时间:2015-04-09 17:53:55

标签: python multiprocessing joblib

joblib文档包含以下警告:

  

在Windows下,保护代码的主循环非常重要   避免在使用joblib.Parallel时递归生成子进程。   换句话说,您应该编写如下代码:

import ....

def function1(...):
    ...

def function2(...):
    ...

... if __name__ == '__main__':
    # do stuff with imports and functions defined about
    ...
     

没有代码应该在“if __name__ =='__ main__'”块之外运行,   只有进口和定义。

最初,我认为这只是为了防止偶然传递给joblib.Parallel的函数递归地调用模块的奇怪情况,这意味着它通常是良好的做法,但通常是不必要的。但是,对我而言,为什么这只会对Windows造成风险是没有意义的。此外,this answer似乎表明无法保护主循环导致代码运行速度比非简单的非递归问题慢几倍。

出于好奇,我从joblib文档中运行了一个非常简单的尴尬并行循环示例,而没有保护Windows框中的主循环。我的终端被垃圾邮件发送了以下错误,直到我关闭它:

ImportError: [joblib] Attempting to do parallel computing without protecting your import on a system that does not suppo
rt forking. To use parallel-computing in a script, you must protect you main loop using "if __name__ == '__main__'". Ple
ase see the joblib documentation on Parallel for more information

我的问题是,如果要在每种情况下保护主循环,那么joblib的windows实现会怎样?

如果这是一个超级基本问题,请道歉。我是并行化世界的新手,所以我可能只是缺少一些基本概念,但我无法在任何地方找到这个问题。

最后,我想指出这纯粹是学术性的;我理解为什么以这种方式编写一个代码是generally good practice,并且无论joblib如何都会继续这样做。

2 个答案:

答案 0 :(得分:22)

这是必要的,因为Windows没有fork()。由于此限制,Windows需要在其生成的所有子进程中重新导入__main__模块,以便在子进程中重新创建父进程状态。这意味着如果您拥有在模块级别生成新进程的代码,那么它将在所有子进程中以递归方式执行。 if __name__ == "__main__"保护用于防止在子进程中重新执行模块范围的代码。

这在Linux上是不必要的,因为 具有fork(),这允许它分叉维护父级相同状态的子进程,而无需重新导入__main__模块。

答案 1 :(得分:5)

万一有人在 2021 年偶然发现: 由于 joblib>0.12 使用的新后端“loky”保护主 for 循环不再需要。见https://joblib.readthedocs.io/en/latest/parallel.html