
进程间不共享内存,变量修改不互通
很多人误以为 multiprocessing 中的全局变量或函数内变量能像线程(threading)那样被多个进程“看到”。实际上,每个子进程启动时会完整复制父进程的内存空间,之后各自独立运行。你在子进程中修改某个变量,父进程和其他子进程完全感知不到。
例如:
counter = 0def worker():
global counter
counter += 1 # 这个修改只在当前子进程生效
if __name__ == '__main__':
from multiprocessing import Process
ps = [Process(target=worker) for _ in range(3)]
for p in ps: p.start()
for p in ps: p.join()
print(counter) # 输出仍是 0
正确做法:用 multiprocessing.Value、multiprocessing.Array 或 multiprocessing.Manager 等支持跨进程共享的对象。
main 模块保护必须加 if __name__ == '__main__'
在 Windows 和部分 macOS 环境下,multiprocessing 默认使用 spawn 启动方式(而非 fork),意味着子进程会重新导入主模块。如果没加保护,子进程一启动就会再次执行创建进程池、启动新进程等逻辑,导致无限递归创建进程,最终报错或卡死。
立即学习“Python免费学习笔记(深入)”;
常见错误写法:
def f(): print('hello')
p = Process(target=f)
p.start() # ❌ 没有保护,Windows 下可能崩溃
务必写成:
if __name__ == '__main__':p = Process(target=f)
p.start()
p.join()
进程池(Pool)返回值需显式获取,不能直接赋值
调用 pool.apply_async() 或 pool.map_async() 时,返回的是 AsyncResult 对象,不是真实结果。直接打印或使用该对象本身,得到的是类似 <multiprocessing.pool.asyncresult at></multiprocessing.pool.asyncresult> 的东西,不是你想要的计算结果。
常见误区:
res = pool.apply_async(func, (x,))print(res) # ❌ 打印的是 AsyncResult 对象
正确方式:
- 用
.get(timeout=...)阻塞等待结果(注意超时避免永久挂起) - 用
.ready()轮询判断是否完成 - 对
map/starmap类方法,直接用同步版本(如pool.map())更简单
子进程异常默认不抛给主进程,容易“静默失败”
当子进程内部发生未捕获异常时,multiprocessing 默认不会中断主进程,也不会打印 traceback,尤其在使用 Pool 时,异常可能被吞掉,只返回一个空结果或直接卡住。
排查建议:
- 在 worker 函数中主动捕获异常并打印日志
- 用
pool.apply_async(..., error_callback=...)显式注册错误处理函数 - 调试阶段优先用
pool.map()(同步阻塞),异常会直接冒泡到主进程 - 避免在子进程中使用依赖标准输出/输入的调试语句(如 print),因重定向可能导致看不到输出










