Python Multiprocessing未使用time.sleep时异常崩溃问题咨询
问题原因解析
核心触发点
这个错误是macOS平台Python 3.8+版本多进程默认spawn启动模式的竞态问题,和你注释掉sleep后任务执行速度大幅提升直接相关。
具体原理
- macOS从Python 3.8开始,多进程默认启动方式从
fork改为spawn:spawn模式启动子进程时,父进程需要先把队列、信号量等同步对象的状态序列化后传给子进程,子进程反序列化这些状态、重建对应内核资源后才能正常运行。 - 你注释掉
sleep后,mul和plus函数的计算量极小,所有任务会在极短时间内执行完成:主进程从done_queue获取完所有结果、向任务队列写入4个STOP标记后,test函数就执行完毕,主进程会直接退出,操作系统会回收主进程持有的所有内核资源,包括队列底层依赖的SemLock信号量对应的文件句柄。 - 而spawn模式启动子进程有一定开销,部分子进程此时还没完成启动流程,还在执行反序列化重建
SemLock的逻辑,对应的内核资源已经被系统回收,就会抛出你看到的FileNotFoundError异常。 - 原代码保留
sleep时,每个任务执行都会有延迟,主进程会长时间阻塞在done_queue.get()调用上等待结果,不会提前退出,所有子进程都有足够时间完成启动,因此不会触发问题。
修复方案
原官方示例只是演示多进程队列的基础用法,没有加子进程等待逻辑,实际生产环境使用时,在所有任务下发完成后需要调用join等待所有子进程退出,避免主进程提前释放资源:
def test(): NUMBER_OF_PROCESSES = 4 TASKS1 = [(mul, (i, 7)) for i in range(20)] TASKS2 = [(plus, (i, 8)) for i in range(10)] # Create queues task_queue = Queue() done_queue = Queue() # Submit tasks for task in TASKS1: task_queue.put(task) # 存储所有子进程对象 processes = [] # Start worker processes for i in range(NUMBER_OF_PROCESSES): p = Process(target=worker, args=(task_queue, done_queue)) p.start() processes.append(p) # Get and print results print('Unordered results:') for i in range(len(TASKS1)): print('\t', done_queue.get()) # Add more tasks using `put()` for task in TASKS2: task_queue.put(task) # Get and print some more results for i in range(len(TASKS2)): print('\t', done_queue.get()) # Tell child processes to stop for i in range(NUMBER_OF_PROCESSES): task_queue.put('STOP') # 新增:等待所有子进程正常退出后,主进程再退出 for p in processes: p.join()
添加join逻辑后,哪怕完全注释掉两个函数里的sleep调用,程序也可以正常运行不会崩溃。
内容的提问来源于stack exchange,提问作者akaButters
相关产品推荐
相关产品推荐

