我是一般并行化的新手,尤其是 concurrent.futures。我想对我的脚本进行基准测试并比较使用线程和进程之间的差异,但我发现我什至无法运行它,因为在使用 ProcessPoolExecutor
时我无法使用我的全局变量。
The following code will output Hello
as I expect, but when you change ThreadPoolExecutor
for ProcessPoolExecutor
, it will output None
.
from concurrent.futures import ProcessPoolExecutor, ThreadPoolExecutor
greeting = None
def process():
print(greeting)
return None
def main():
with ThreadPoolExecutor(max_workers=1) as executor:
executor.submit(process)
return None
def init():
global greeting
greeting = 'Hello'
return None
if __name__ == '__main__':
init()
main()
我不明白为什么会这样。在我的真实程序中,init 用于将全局变量设置为 CLI 参数,并且有很多。因此,似乎不推荐将它们作为参数传递。那么如何将这些全局变量正确地传递给每个进程/线程呢?
我知道我可以改变周围的事情,这会奏效,但我不明白为什么。例如,以下适用于两个执行器,但这也意味着必须对每个实例进行全局初始化。
from concurrent.futures import ProcessPoolExecutor, ThreadPoolExecutor
greeting = None
def init():
global greeting
greeting = 'Hello'
return None
def main():
with ThreadPoolExecutor(max_workers=1) as executor:
executor.submit(process)
return None
def process():
init()
print(greeting)
return None
if __name__ == '__main__':
main()
所以我的主要问题是, 实际发生了什么。为什么这段代码适用于线程而不适用于进程?而且,我如何正确地将 set globals 传递给每个进程/线程,而不必为每个实例重新初始化它们?
(旁注:因为我读过 concurrent.futures 在 Windows 上的行为可能不同,所以我必须注意我在 Windows 10 64 位上运行 Python 3.6。)
原文由 Bram Vanroy 发布,翻译遵循 CC BY-SA 4.0 许可协议
我不确定这种方法的局限性,但您可以在主进程/线程之间传递(可序列化?)对象。这也将帮助您摆脱对全局变量的依赖:
适用于两种执行器类型。
编辑:尽管听起来这对您的用例来说不是问题,但我会指出
ProcessPoolExecutor
,opts
dict 你进入process
将是一个冻结的副本,因此对它的更改在进程中不可见,一旦您返回到__main__
块,它们也将不可见。ThreadPoolExecutor
另一方面,将在线程之间共享 dict 对象。