multiprocessing调用join后仍存僵尸进程,求代码问题排查及改写方案
搞定Python多进程里的僵尸进程问题
兄弟,我来帮你排查这两个僵尸进程的问题,其实核心都是进程资源没被正确回收导致的,咱们逐个说:
第一个代码的问题:加了join()还是有僵尸?
你这段代码里虽然加了join(),但可能是因为两个潜在问题导致僵尸残留:
- 子进程可能因为异常或者
Queue的管道问题没有正常退出,导致父进程的join()没正确触发回收 - 原代码的写法虽然逻辑上没问题,但缺少对异常进程的兜底处理
我给你调整一下写法,确保每个进程都被彻底回收:
def stats_wrapper(a,b,c,d): q = mp.Queue() processes = [] # 单独创建每个进程并存到列表,方便后续管理 for b1 in b: p = mp.Process(target=stats, args=(a, {b1: b[b1]}, c, d, q)) processes.append(p) p.start() results = [] # 先获取所有队列结果(这里会阻塞到每个子进程都把数据放进来) for _ in range(len(processes)): results.append(q.get()) # 逐个等待子进程结束,加超时避免卡死,异常进程直接终止再回收 for p in processes: p.join(timeout=5) # 如果进程还活着,强制终止后再join一次确保回收 if p.is_alive(): p.terminate() p.join() return results
这么改的原因:
- 确保每个进程都被
join,即使进程因为某种原因挂起,超时后会强制终止并回收资源 - 避免因为
Queue的内部资源未释放导致的进程残留
第二个代码的重构:怎么加join()?
你这段代码的核心坑是没保存创建的Process实例,直接mp.Process(...).start()后就丢了引用,根本没法调用join()!必须把每个进程存到列表里,之后才能逐个回收:
重构后的代码:
q = mp.Queue() jobs = (func1, func2, func3) args = ((arg1, arg2, arg3), (arg2, arg3), (arg1, arg4)) # 先创建一个列表存所有进程实例 processes = [] for job, arg in zip(jobs, args): p = mp.Process(target=job, args=arg, name=str(job.__name__)) processes.append(p) p.start() result = [] # 注意!你之前写的len(job)是错的,应该是len(processes)或者len(jobs) for _ in range(len(processes)): result.append(q.get()) # 现在可以逐个join回收进程了 for p in processes: p.join(timeout=5) if p.is_alive(): p.terminate() p.join()
这里还有个小错误要注意:你原来的range(len(job))是笔误,job是单个函数,len(job)会报错,改成len(processes)才对,不然要么卡住要么少拿结果。
最后总结下避免僵尸的关键:
- 一定要保存Process实例:别随手创建随手启动就丢了,必须存到列表里方便后续管理
- 每个进程都要join:
join()就是父进程等着子进程结束后收尸,不调用的话系统就留着僵尸进程占资源 - 兜底异常进程:给
join()加超时,挂起的进程直接terminate()再join(),确保彻底回收 - Queue用对:
multiprocessing.Queue要确保子进程都正常put数据,避免因为管道阻塞导致进程残留
内容的提问来源于stack exchange,提问作者WitchKingofAngmar
相关产品推荐
相关产品推荐

