24

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 上存在风险。此外,这个答案似乎表明未能保护主循环导致代码运行速度比其他非常简单的非递归问题慢几倍。

出于好奇,我从 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 实现需要在每种情况下都保护主循环吗?

抱歉,如果这是一个超级基本的问题。我是并行化世界的新手,所以我可能只是遗漏了一些基本概念,但我在任何地方都找不到明确讨论的这个问题。

最后,我想指出,这纯粹是学术性的;我理解为什么以这种方式编写代码通常是一种好习惯,并且将继续这样做,而不管 joblib。

4

2 回答 2

29

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

这在 Linux 上不是必需的,因为它确实具有fork(),这允许它派生一个保持父进程相同状态的子进程,而无需重新导入__main__模块。

于 2015-04-09T18:44:51.780 回答
5

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

于 2021-01-08T09:13:25.670 回答