使用multiprocessing时触发EOFError: Ran out of Input错误如何解决?
问题原因排查
直接触发EOFError: Ran out of Input的核心原因
- 你运行代码的系统大概率是Windows,Python的
multiprocessing模块在Windows下默认使用spawn模式启动子进程:子进程会重新导入整个主模块,同时需要把Process传入的target、参数全部通过pickle序列化后传给子进程,序列化失败或者子进程读取序列化数据异常就会触发这个报错。 - 你在死循环里每次处理帧都新建一个Process实例,高频创建销毁进程的开销极高,且每次都要序列化帧、
obd实例对象:你的obd实例里包含YOLO模型、加载的权重等无法被pickle序列化的资源,序列化直接失败就会报EOF错误。
代码里的其他致命逻辑错误
Process.start()方法没有返回值,你写的frame=Process(target=obd.predictYolo, args=(frame,)).start()会直接把frame赋值为None,后续传给showFrames的就是空值,哪怕没有多进程报错也无法正常展示。- 你的多进程没有做生命周期管理:既没有
join回收子进程资源,也没有控制并发数量,运行几秒后进程数就会爆炸,直接占满系统资源。 - 你直接把类实例方法
obd.predictYolo作为子进程target,multiprocessing会尝试序列化整个obd实例传到子进程,哪怕你没有显式传实例作为参数也会触发序列化逻辑。
修复方案
调整架构思路
不要每次处理帧都新建进程,全局只启动1个(或固定数量)检测子进程,用multiprocessing.Queue在主进程和检测进程之间传递原始帧、处理后的帧,完全避免频繁创建进程和不可序列化对象的传递。
修复后示例代码
from multiprocessing import Process, Queue import sys import cv2 from typing import Union from threading import Thread import videoPlayerThreading as vpt # 检测逻辑改成顶层函数,在子进程内部初始化模型,避免序列化 def detection_worker(input_q: Queue, output_q: Queue): from objDect import objDect as od # 模型在子进程里初始化,不用序列化传到子进程 obd = od(videoSources=0) while True: frame = input_q.get() if frame is None: # 收到结束信号退出 break processed_frame = obd.predictYolo(frame) output_q.put(processed_frame) def main(videoSource): # 初始化队列,设置最大长度避免帧堆积 input_q = Queue(maxsize=2) output_q = Queue(maxsize=2) # 全局只启动一个检测进程 det_process = Process(target=detection_worker, args=(input_q, output_q)) det_process.start() getFrame = vpt.getFrames(videoSource).start() showFrame = vpt.showFrames(videoSource).start() while True: if not getFrame.doVideo or not showFrame.doVideo: # 发结束信号给检测进程 input_q.put(None) det_process.join() getFrame.stop() showFrame.stop() cv2.destroyAllWindows() sys.exit() # 读原始帧 raw_frame = getFrame.frame if raw_frame is None: continue # 队列没满就送帧去检测 if not input_q.full(): input_q.put(raw_frame) # 有处理完的帧就取出来展示 if not output_q.empty(): showFrame.frame = output_q.get() if __name__=="__main__": main(0)
额外优化建议
- 你现有的
getFrames和showFrames类没有做线程安全的读写锁,多线程同时读写self.frame可能会出现半帧、花屏的问题,建议给frame的读写加threading.Lock锁。 - 队列设置合理的最大长度,避免处理速度跟不上读帧速度导致内存暴涨。
内容的提问来源于stack exchange,提问作者Albert
相关产品推荐
相关产品推荐

