Python多进程中未读取Queue数据时子进程不退出的原因
为什么multiprocessing的Queue未取数据时子进程无法终止?
首先得给你拆解下multiprocessing.Queue的底层逻辑——它可不是一个简单的内存队列,背后是管道+锁+后台线程的组合体,这也是问题的根源所在。
咱们对应你的代码场景一步步捋清楚:
- 主进程创建Queue后启动子进程,子进程调用
q.put()把那个包含10万条数据的大列表塞进去。这里要注意:数据不是直接扔进主进程的Queue内存里,而是先写到管道中(管道是进程间通信的底层机制,有固定的缓冲区大小)。 - 主进程里有个默默干活的feeder线程,它的核心任务就是不断从管道另一端读取数据,再把数据转存到Queue的内部内存缓冲区中。
- 当你注释掉所有
q.get()时,主进程从来没去取Queue里的数据,时间一长Queue的内部缓冲区就被填满了,feeder线程也就没法继续从管道里读取数据。这连锁导致管道的缓冲区也被占满,子进程那边虽然已经执行完put()后的打印代码,但它在退出前必须完成一项关键清理工作:确保所有通过Queue发送的数据都被主进程接收(防止数据丢失)。可管道里的数据还没被feeder线程取走,子进程就卡在这一步,没法真正终止。 - 主进程的
p.join()是用来等待子进程完全退出的,子进程卡着不结束,主进程自然就一直阻塞在join()这儿了。
那为什么取消任意一处q.get()就正常运行了?
- 如果在主进程调用
q.get():会从Queue的内部缓冲区取走数据,腾出空间后feeder线程就能继续读取管道里的剩余数据,管道缓冲区也随之清空,子进程的清理工作能顺利完成,自然就正常退出了。 - 如果在子进程调用
q.get():相当于把刚放进去的数据又取了出来,Queue内部缓冲区和管道都没被占用,子进程退出时没有牵挂,直接就能结束。
再对应你的测试输出看:
- 注释
get()时,输出到bef join就卡住,正是因为子进程卡在退出前的清理步骤,主进程的join()一直等不到子进程终止。 - 取消
get()后,子进程能顺利完成退出流程,主进程的join()执行完毕,就能打印aft join了。
内容的提问来源于stack exchange,提问作者user3282758
相关产品推荐
相关产品推荐

