问题:在使用multiprocessing.Queue进行多进程传递数据时,明明进程已经执行完毕,却在执行join()时发生不明阻塞。
代码:
from multiprocessing import Process, Queue, current_process
def main():
plist = []
queue = Queue()
for i in range(8):
plist.append(Process(target=run, args=(queue,)))
for i in plist:
i.start()
for i in plist:
# 在这里被阻塞
print(i.name + "----join")
i.join()
while not queue.empty():
print(queue.get())
def run(queue):
# 64以及以下正常结束 65以及以上阻塞
# 出问题数量似乎和put内容的大小有关
for i in range(64):
queue.put("123---")
print(current_process().name + "--end")
if __name__ == "__main__":
main()
正常运行结果:
因不明原因,主进程在join()处被阻塞:
原因:
通过查阅文档发现:
如果一个子进程将一些对象放进队列中 (并且它没有用JoinableQueue.cancel_join_thread
方法),那么这个进程在所有缓冲区的对象被刷新进管道之前,是不会终止的。(if a child process has put items on a queue (and it has not usedJoinableQueue.cancel_join_thread
), then that process will not terminate until all buffered items have been flushed to the pipe.)
这意味着,除非你确定所有放入队列中的对象都已经被消费了,否则如果你试图等待这个进程,你可能会陷入死锁中。相似地,如果该子进程不是后台进程,那么父进程可能在试图等待所有非后台进程退出时挂起。(This means that if you try joining that process you may get a deadlock unless you are sure that all items which have been put on the queue have been consumed. Similarly, if the child process is non-daemonic then the parent process may hang on exit when it tries to join all its non-daemonic children.)
注意用管理器创建的队列不存在这个问题。
因此,在使用Queue进行进程通信时,最好边put边get,防止死锁。
参考文档:https://docs.python.org/zh-cn/3/library/multiprocessing.html#multiprocessing.Process