在python 3.6或3.7中将multiprocessing.Pool
与maxtasksperchild=1
一起使用时,我注意到由池产生的某些进程正在挂起并且不会退出,即使已执行其任务的回调。结果,Pool.join()
将永远阻塞,即使所有任务都已完成。在进程树中,可以看到正在运行但空闲的子进程。如果maxtasksperchild=None
不会发生此问题。
问题似乎与回调函数的确切功能有关。文档point out that the callback "should return immediately",因为它将阻止管理该池的其他线程。
在我的计算机上重现此行为的一个最小示例如下:(在它不会永远阻塞时,进行一些尝试或增加任务数。)
from multiprocessing import Pool
from os import getpid
from random import random
from time import sleep
def do_stuff():
pass
def cb(arg):
sleep(random()) # can be replaced with print('foo')
p = Pool(maxtasksperchild=1)
number_of_tasks = 100 # a value may depend on your machine -- for mine 20 is sufficient to trigger the behavior
for i in range(number_of_tasks):
p.apply_async(do_stuff, callback=cb)
p.close()
print("joining ... (this should take just seconds)")
print("use the following command to watch the process tree:")
print(" watch -n .2 pstree -at -p %i" % getpid())
p.join()
与我的预期相反,即使p.join()
和do_stuff
都被调用了100次,最后一行中的cb
也会永远阻塞。
我知道sleep(random())
违反了文档,但是print()
是否也花费了太长的时间?文档的编写方式表明,为了提高性能和效率,需要使用非阻塞的回调函数,并且不清楚“慢速”的回调函数会完全破坏池。
print()
回调函数中禁止multiprocessing.Pool
? (如何替换该功能?什么是“立即返回”,什么不是?)