为啥在使用 joblib.Parallel 时保护主循环很重要?
Posted
技术标签:
【中文标题】为啥在使用 joblib.Parallel 时保护主循环很重要?【英文标题】:Why is it important to protect the main loop when using joblib.Parallel?为什么在使用 joblib.Parallel 时保护主循环很重要? 【发布时间】:2015-06-15 05:43:13 【问题描述】: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。
【问题讨论】:
【参考方案1】:这是必要的,因为 Windows 没有 fork()
。由于这个限制,Windows 需要在它产生的所有子进程中重新导入您的__main__
模块,以便在子进程中重新创建父进程的状态。这意味着如果您有在模块级别生成新进程的代码,它将在所有子进程中递归执行。 if __name__ == "__main__"
守卫用于防止模块范围内的代码在子进程中重新执行。
这在 Linux 上不是必需的,因为它确实有 fork()
,这允许它派生一个保持与父进程相同状态的子进程,而无需重新导入 __main__
模块。
【讨论】:
有趣,谢谢!我不得不说,如果我正在设计一个操作系统,我会认为 fork 进程的能力将是非常基本和可取的......但我想这只是 windows 的另一个奇怪的限制。【参考方案2】:如果有人在 2021 年偶然发现此问题: 由于 joblib>0.12 使用的新后端“loky”不再需要保护主 for 循环。见https://joblib.readthedocs.io/en/latest/parallel.html
【讨论】:
以上是关于为啥在使用 joblib.Parallel 时保护主循环很重要?的主要内容,如果未能解决你的问题,请参考以下文章
在 joblib `Parallel` 上下文中腌制 `matlab` 对象时出错
joblib.Parallel 是不是保持传递数据的原始顺序?
即使添加了“如果 __name__ == '__main__':”,Windows 上的 python joblib Parallel 也无法正常工作
为啥我的受 AAD 保护的 Azure 函数在使用来自 UWP 应用的访问令牌调用时返回 401?