joblib文档包含以下警告:
在Windows下,重要的是保护代码的主循环,以避免在使用joblib.Parallel时递归产生子进程。换句话说,您应该编写如下代码: import .... def function1(...): ... def function2(...): ... ... if __name__ == '__main__': # do stuff with imports and functions defined about ... 任何代码都不应在“如果__name__ ==’main‘”块之外运行,只能导入和定义。
在Windows下,重要的是保护代码的主循环,以避免在使用joblib.Parallel时递归产生子进程。换句话说,您应该编写如下代码:
import .... def function1(...): ... def function2(...): ... ... if __name__ == '__main__': # do stuff with imports and functions defined about ...
任何代码都不应在“如果__name__ ==’main‘”块之外运行,只能导入和定义。
最初,我认为这只是为了防止偶尔出现奇数情况,在这种情况下函数joblib.Parallel递归地传递给模块,这意味着这通常是一种好习惯,但通常是不必要的。但是,对我而言,这仅是Windows上的风险为什么并没有意义。此外,此答案似乎表明,未能保护主循环导致代码运行速度比针对非常简单的非递归问题的运行速度慢了数倍。
joblib.Parallel
出于好奇,我运行了来自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如何,这种做法都将继续。
这是必要的,因为Windows没有fork()。由于此限制,Windows需要__main__在其产生的所有子进程中重新导入您的模块,以便在子进程中重新创建父进程的状态。这意味着,如果您具有在模块级别生成新进程的代码,它将在所有子进程中递归执行。该if __name__ == "__main__"防护用于防止模块范围内的代码在子进程中重新执行。
fork()
__main__
if __name__ == "__main__"
在Linux上,这不是必需的,因为它 确实 具有fork(),它允许它派生一个子进程,该子进程保持与父进程相同的状态,而无需重新导入__main__模块。