我正在尝试使用ProcessPoolExecutor方法,但是它失败了。 这是一个使用失败的示例(计算两个数字的大除法)。 我不明白这是什么错误
def gcd(pair):
a, b = pair
low = min(a, b)
for i in range(low, 0, -1):
if a % i == 0 and b % i == 0:
return i
numbers = [(1963309, 2265973), (2030677, 3814172),
(1551645, 2229620), (2039045, 2020802)]
start = time()
pool = ProcessPoolExecutor(max_workers=2)
results = list(pool.map(gcd, numbers))
end = time()
print('Took %.3f seconds' % (end - start))
BrokenProcessPool:进程运行中或挂起时,进程池中的进程突然终止。
答案 0 :(得分:0)
将代码更改为如下所示,它将起作用:
from time import time
from concurrent.futures import ProcessPoolExecutor
def gcd(pair):
a, b = pair
low = min(a, b)
for i in range(low, 0, -1):
if a % i == 0 and b % i == 0:
return i
numbers = [(1963309, 2265973), (2030677, 3814172),
(1551645, 2229620), (2039045, 2020802)]
def main():
start = time()
pool = ProcessPoolExecutor(max_workers=3)
results = list(pool.map(gcd, numbers))
end = time()
print('Took %.3f seconds' % (end - start))
if __name__ == '__main__':
main()
在支持fork()
的系统上这不是必需的,因为您的脚本只被导入一次,然后每个启动的ProcessPoolExecutor
进程都已经在全局名称空间中拥有了一个对象副本,例如{ {1}}功能。一旦分叉,他们将经历引导过程,从而开始运行其目标函数(在本例中为工作进程循环,该进程从进程池执行程序接受作业),并且它们从不返回原始状态。分叉的主模块中的代码。
相反,如果您使用的是Windows和OSX上默认的基于gcd
的进程,则必须为每个工作进程从头开始一个新进程,并且如果它们必须重新执行< em> import 您的模块。但是,如果您的模块直接在模块主体中执行类似spawn
的操作,而没有像ProcessPoolExecutor
那样进行保护,那么他们将无法在不启动新的if __name__ == '__main__':
的情况下导入您的模块。因此,您遇到的这个错误实际上是在阻止您创建无限的过程炸弹。
ProcessPoolExecutor
的文档中提到了这一点:
ProcessPoolExecutor
模块必须可由工作程序子进程导入。这意味着__main__
在交互式解释器中将不起作用。
但是他们并没有真正弄清楚为什么ProcessPoolExecutor
模块是“可导入的”是什么或意味着什么。当您使用Python编写一个简单的脚本并像__main__
一样运行它时,您的脚本python foo.py
的模块名称为foo.py
,而不是名为__main__
的模块。如果您foo
,您会得到。在这种情况下,“可导入”实际上意味着可导入,而没有诸如产生新流程之类的主要副作用。