Python多进程Queue关闭后子进程未终止及状态查询问题
多进程与multiprocessing.Queue问题解答
原问题代码
import random import time import multiprocessing def fun(queue_value): sleep_value = random.choice(range(1, 20)) time.sleep(sleep_value) queue_value.put(sleep_value, 3) value = None queue_value = multiprocessing.Queue() process = multiprocessing.Process(target=fun, args=(queue_value,)) # 原代码此处缺少逗号,属于语法错误 process.daemon = True process.start() print('PID', process.pid) #pid shows as 93848 time.sleep(10) # sleeps for 10 sec and then check for the value and the queue will be closed if not queue_value.empty(): print(queue_value.get(timeout=3)) queue_value.close() queue_value.join_thread() # As per the python doc, join_thread() should used only after calling close() process.join() if process.is_alive(): print('process is still alive') process.terminate() print('Is process alive', process.is_alive(), process.exitcode)
问题描述
当fun函数中的sleep_value取值大于10(比如18)时,主进程休眠10秒后关闭并join队列,此时无法获取队列中的值,子进程仍会继续休眠8秒。按照Python文档要求,应在join进程前关闭或join队列,但调用process.join()后子进程仍存活,执行process.terminate()后输出仍显示子进程存活(Is process alive True None)。
问题1:为何子进程未终止?是否因为子进程在queue_value.close()后尝试向队列put值?
另外,主程序结束前用ps -ef未查到该子进程PID,说明子进程已终止。
问题2:如何判断该子进程是否成功退出?
额外问题:采用无Pool的同步多进程方式终止子进程是否可行?有时会产生僵尸进程,该如何处理?
问题解答
问题1解答
先纠正原代码的几个关键错误:
random.choise拼写错误,应为random.choiceargs=(queue_value)缺少逗号,需写成args=(queue_value,),否则会将Queue对象直接作为参数传递,导致函数参数不匹配time.sleep()缺少参数,应为time.sleep(sleep_value)
回到核心问题:
- 子进程在
queue_value.close()后尝试put值时,会触发BrokenPipeError,若未捕获异常,子进程会因未处理的异常直接崩溃退出。 - 你看到
process.is_alive()返回True且exitcode为None,是因为进程状态同步存在延迟:主进程调用terminate()后,操作系统需要时间完成子进程终止操作,而Python的进程对象状态不会立即同步系统状态。但ps -ef查不到PID,说明子进程已经被系统实际终止。
问题2解答
判断子进程是否成功退出,需结合以下几点:
- 优先检查
process.exitcode:只要值不为None,就说明进程已经终止。不同值的含义:exitcode == 0:进程正常退出exitcode > 0:进程因未处理的异常崩溃退出exitcode < 0:进程被系统信号终止(比如SIGTERM对应-15,SIGKILL对应-9)
- 不要仅依赖
is_alive(),可在调用terminate()后短暂休眠(如time.sleep(0.1)),再调用is_alive()或检查exitcode,结果会更准确。 - 直接通过系统工具验证:比如
ps -ef | grep <PID>(Linux)或tasklist(Windows),这是最准确的方式。
额外问题解答
- 无Pool的同步多进程终止子进程完全可行:直接调用
process.terminate()即可向子进程发送终止信号,绝大多数场景下都能正常终止子进程。 - 僵尸进程的处理方案:
- 僵尸进程是子进程终止后,父进程未调用
wait()或join()回收其资源导致的。在Pythonmultiprocessing中,调用process.join()会自动完成资源回收,避免僵尸进程。 - 若设置
process.daemon = True,主进程退出时,所有守护进程会被自动终止并回收资源,不会遗留僵尸进程。 - 避免子进程终止后长时间不调用
join(),确保父进程及时回收子进程资源。
- 僵尸进程是子进程终止后,父进程未调用
内容的提问来源于stack exchange,提问作者Vishak Raj
相关产品推荐
相关产品推荐

