有时对函数pool.close()
的调用需要花费大量时间才能返回,我想了解原因。通常,我会让每个流程返回一个大set
或一个大dict
,main
合并它们。它看起来像这样:
def worker() :
s = set()
# add millions of elements to s
return s
if __name__ == '__main__' :
pool = multiprocessing.Pool( processes=20 )
fullSet = set.union( * pool.imap_unordered( worker, xrange(100) ) )
pool.close() # This takes a LOT OF TIME!
pool.join()
正如我所说,pool.close()
可能需要5分钟,10分钟或更长时间才能返回。使用词典而不是集合时会出现同样的问题。这就是documentation关于close
所说的内容:
防止将更多任务提交到池中。一切都结束了 任务已经完成,工作进程将退出。
我想我不明白发生了什么。在fullSet = ...
行之后,所有的工作都完成了,我不再需要工人了。他们在做什么花了这么多时间?
答案 0 :(得分:3)
Pool.close
这么长时间不太可能。仅仅因为这是the source of close
def close(self):
debug('closing pool')
if self._state == RUN:
self._state = CLOSE
self._worker_handler._state = CLOSE
所有发生的事情都是一些状态变量发生了变化。这对该方法的运行时没有可测量的影响,也不会导致它稍后返回。您可以假设close
立即返回 。
现在,更有可能的是,你的pool.join()
行是这种延迟的“罪魁祸首”。但它只是在做its job:
等待工作进程退出。
它实质上在池中的每个进程上调用join
。如果您要加入流程或线程,则正在等待以完成其工作并终止。
因此,在您的情况下,您运行了20个进程,为一组添加了一百万个元素。这需要一段时间。为了使你的主进程不要提前退出(导致子进程死机),你正在等待工作进程完成他们的工作;加入他们。因此,您所经历的工作可能会对您的工作量产生什么影响。
旁注:如果在工作函数中执行繁重的CPU工作,则不应产生比CPU具有可用硬件线程更多的进程,因为您只会从管理和切换进程中引入额外的开销。例如,对于消费者Core i7,此数字为8。
答案 1 :(得分:0)
可能是pool.imap_unordered
和后续set.union
结果的迭代需要很长时间。
每个工人完成一套装置后,必须将其腌制,送回原始工艺并进行打开。这需要时间和记忆。然后*
必须解压缩union
的所有集合才能处理。
使用map_async
可能会获得更好的结果。让回调将返回的集合附加到列表中,并在每个集合上使用union
循环遍历该列表。