繁体   English   中英

为什么从另一个模块提交 function 时,Windows 上的 ProcessPoolExecutor 需要 __main__ 守卫?

[英]Why ProcessPoolExecutor on Windows needs __main__ guard when submitting function from another module?

假设我有一个程序

import othermodule, concurrent.futures
pool = concurrent.futures.ProcessPoolExecutor()

然后我想说

fut = pool.submit(othermodule.foo, 5)
print(fut.result())

官方文档说我需要用if __name__ == '__main__'来保护后两个语句。 这并不难,我只是想知道为什么 foo存在于othermodule中,它知道( foo.__module__ == 'othermodule' )。 5 是字面量 int。 两者都可以在不引用创建池的模块的情况下被 pickle 和 unpickled。 我看不出为什么 ProcessPoolExecutor 必须在另一边导入它。

我的 model 是这样的:你启动另一个 python 进程,pickle othermodule.foo5 ,然后通过某种 IPC 方法(队列,Pipe,等等)发送它们。 另一个进程解开它们(当然导入othermodule以查找foo的代码),然后调用foo(5) ,将结果发回(再次通过 pickle 和一些 IPC)。 很明显我的model是错的,但是我想知道错在哪里。

这可能是唯一的原因,在 Unix 上,这是通过分叉__main__解决的,所以在 Windows(分叉实际上不起作用)上,他们做了最接近程序的模仿,而不是最接近意图的模仿? 这样的话,能固定在Windows吗?

(是的,我知道Why does Python's multiprocessing module import __main__ when starting a new process on Windows? 。在我看来,它回答了一个稍微不同的问题。但你可以尝试用它的答案向我解释为什么这个问题的答案必须相同。)

老问题,但现在有一个很好的答案。

这可能是唯一的原因,在 Unix 上,这是通过分叉__main__解决的,所以在 Windows(分叉实际上不起作用)上,他们做了最接近程序的模仿,而不是最接近意图的模仿? 这样的话,能固定在Windows吗?

我猜想编写多处理库的人是在假设 os.fork() 可用的情况下编写的。 在 windows 上,这被以一种 hacky 的方式绕过了。 事实上,直到今天(2022 年),python 的内置并行化模块multiprocessingconcurrent.futures仍然很难使用,主要是因为 pickling 错误。 当解释器可以分叉时,这些模块工作得最好,不需要 pickle 任何东西。

它可以固定在 Windows 上。有一个名为loky的 package,您可以使用 pip 或 conda 安装。 它使用名为cloudpickle的改进 pickling 模块(也必须安装)来调用主模块中的函数。 因此,子进程不需要导入主模块,因此不必使用if __name__ == '__main__'守卫。 (链接到 loky 的github repo 和doc )您还可以尝试更高级别的 package joblib,它使用 loky 作为其后端并且也具有相同的行为。

Loky 也有一个使用可重用执行器的工具(即一个进程池,可以一次又一次地重用以减少产生的开销)。 您可以在此处查看示例。 Loky 本质上使用了来自concurrent.futuresProcessPoolExecutor的语义,但在底层有不同的实现。

我将举一个单一执行者(不可重用)的例子。

import os

def f(x):
  return os.getpid()

with loky.ProcessPoolExecutor(max_workers=3) as pool:
    jobs = [pool.submit(f,i) for i in range(3)]  # returns Future() instances
    results = [job.result() for job in jobs]  # get results from Future

print(results)

在 Windows 上运行它,它应该毫无障碍地返回子进程的 PID,并且不需要使用if __name__=='__main__'

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM