多进程适合CPU密集型任务,因GIL限制多线程无法提升Python的CPU性能;I/O密集型可用threading或asyncio;混合场景应拆分处理,避免GIL与阻塞互相拖累。
这是由 GIL(全局解释器锁)决定的:CPython 中同一时刻只有一个线程能执行 Python 字节码。所以即使开了 10 个 threading.Thread 做数值计算,实际仍是串行执行,还多了线程切换开销。
常见错误现象:time.time() 测出来多线程比单线程还慢;top 或任务管理器显示 CPU 占用率始终卡在 100%(单核),而不是接近 N×100%。
适用场景:
multiprocessing
threading 或 asyncio 都可,前者更简单multiprocessing.Pool 比手动创建 Process 更省心也更高效直接用 Process 启动几十个子进程容易失控:进程生命周期难管理、结果收集要自己搞共享内存或队列、异常传播困难

Pool 封装了进程复用、任务分发、结果聚合和错误回传。
实操建议:
pool.map(func, iterable) 替代循环调用 Process(target=func, args=(x,))
iterable 会被序列化(pickle),不能传 lambda、嵌套函数、带绑定方法的对象os.cpu_count(),CPU 密集任务别盲目设更大值,反而因调度开销拖慢整体concurrent.futures.ThreadPoolExecutor 是 I/O 任务的首选相比原始 threading 模块,它自动管理线程生命周期、支持 as_completed 和超时控制,且 API 与 ProcessPoolExecutor 一致,方便后续替换为多进程。
典型误用:
ThreadPoolExecutor 跑纯计算(比如 sum([i**2 for i in range(10**6)]))→ 白忙活,GIL 锁死shutdown(wait=True) 或没用 with 上下文 → 程序可能提前退出,任务被丢弃比如“下载图片 → 缩略图处理”这种组合任务,不能全扔给线程(缩略图卡 GIL),也不能全扔给进程(下载部分启动开销大、上下文切换重)。
推荐做法:
ThreadPoolExecutor 下载一批图片(I/O 并发)ProcessPoolExecutor 批量做缩略图(CPU 并发)最容易被忽略的是:子进程无法继承主线程的 TLS(线程局部存储)、数据库连接、日志 handler 等资源,初始化必须放在子进程内部,不能靠父进程传入。