子进程崩溃时主进程默认收不到异常,需通过Queue、Pipe或Pool的error_callback显式传递;推荐用Queue在子进程中捕获并发送异常信息,主进程join后取值并重新raise。

子进程崩溃时主进程收不到异常?这是默认行为
multiprocessing 默认不会把子进程的异常传播回主进程。子进程一出错就静默退出,Process.join() 返回后主进程根本不知道它挂了,更别说拿到 traceback。这不是 bug,是设计使然——子进程与主进程内存隔离,异常对象无法直接跨进程传递。
要让主进程感知并处理子进程异常,必须主动捕获、序列化、再反序列化。Python 标准库提供了现成路径,但需要你显式调用。
用 multiprocessing.Queue 传异常信息最稳妥
Queue 是 multiprocessing 中少数能安全跨进程传递 Python 对象的机制之一,支持 Exception 实例(只要它可被 pickle 序列化)。
实操建议:
立即学习“Python免费学习笔记(深入)”;
- 在子进程中用
try/except捕获所有异常,把sys.exc_info()或traceback.format_exc()结果塞进Queue - 主进程在
join()后立刻从Queue尝试取值;若取出的是异常对象,直接raise它 - 别依赖
Queue.get_nowait()—— 可能因调度时序漏掉,改用带超时的get(timeout=0.1)并捕获queue.Empty - 确保
Queue在子进程启动前创建,并作为参数传入target函数
示例关键片段:
让 macOS 自动化像说话一样简单 —— 用代码控制你的 Mac,无需学习 AppleScript 系统要求 macOS 14+ (Sonoma) Python 3.9+ 需要开启:辅助功能 + 屏幕录制权限
def worker(q):
try:
1 / 0
except Exception:
import traceback, sys
q.put((sys.exc_info()[0], sys.exc_info[1], traceback.format_exc()))
<p>if <strong>name</strong> == '<strong>main</strong>':
q = multiprocessing.Queue()
p = multiprocessing.Process(target=worker, args=(q,))
p.start()
p.join()
if not q.empty():
exc_type, exc_value, exc_tb = q.get()
raise exc_value # 或 raise exc_type(exc_value).with_traceback(...)
Pool.apply_async 的 error_callback 能自动触发但有局限
Pool 提供了更高级的抽象:apply_async(..., error_callback=...)。当子任务抛异常时,该回调会在主进程中执行,参数就是异常对象。
但要注意:
- 只对
apply_async有效,map_async等不支持 - 回调函数运行在主进程,但异常对象已被反序列化,原始 traceback 的文件路径和行号可能失效(尤其跨平台或不同 Python 版本)
- 不能中断其他正在运行的子任务——异常只通知,不终止整个
Pool - 如果没设
error_callback,异常会被吞掉,和普通Process一样静默
别碰 multiprocessing.Manager().dict() 传异常
有人想用 Manager 共享字典存异常,这很危险:Exception 实例在 Manager 子进程中会被深度拷贝,但部分属性(如 <strong>traceback</strong>)不可序列化,会触发 TypeError: can't pickle traceback objects。
真正能跨进程可靠传递异常信息的,只有三种方式:
-
Queue(推荐,简单可控) -
Pipe(比Queue轻量,但只能两点通信) -
Pool的error_callback(适合批量任务,封装度高)
绕开这些机制硬搞共享内存或全局变量,大概率卡在 pickle 错误上,而且调试成本远高于老实用 Queue。

















