python threading在cpu密集型任务中几乎无效,根本原因是cpython的gil强制同一时刻仅一个线程执行python字节码,导致多线程实为串行执行,甚至因线程切换开销而更慢;仅适用于io密集型任务,cpu密集型任务必须改用multiprocessing或processpoolexecutor。

为什么 threading 在 CPU 密集型任务中几乎没用
Python 的 threading 模块跑不起来真正的并行计算,根本原因是 GIL(全局解释器锁)——同一时刻只有一个线程能执行 Python 字节码。你开 16 个 Thread 去做矩阵乘法或解析大 JSON,实际还是串行跑,甚至因线程切换更慢。
常见错误现象:top 显示 CPU 占用率卡在 100%(单核满载),其他核心闲置;任务耗时和单线程几乎一样。
- 适用场景:仅适合 I/O 密集型任务(如 HTTP 请求、文件读写),此时线程会在等待时释放 GIL
- 不适用场景:数值计算、图像处理、正则匹配大量文本等纯 CPU 工作
- 替代方案:必须用
multiprocessing或concurrent.futures.ProcessPoolExecutor
用 ProcessPoolExecutor 替代手动管理 multiprocessing 进程
直接写 multiprocessing.Process 容易出错:进程间通信复杂、异常难捕获、资源清理漏掉导致僵尸进程。而 concurrent.futures.ProcessPoolExecutor 封装了这些细节,接口接近 ThreadPoolExecutor,迁移成本低。
实操建议:
- 把计算函数设计成纯函数(无全局状态、无副作用),方便序列化传入子进程
- 避免传递大型对象——
executor.map()会 pickle 参数,大数组反复序列化反而拖慢速度;优先用numpy+shared_memory(Python 3.8+)或提前切片分发 - 设置
max_workers:一般设为os.cpu_count(),但若任务本身含较多 I/O 或内存带宽瓶颈,可适当调低
示例:
from concurrent.futures import ProcessPoolExecutor import os <p>def cpu_intensive_task(x): return sum(i * i for i in range(x))</p><p>if <strong>name</strong> == '<strong>main</strong>': with ProcessPoolExecutor(max_workers=os.cpu_count()) as executor: results = list(executor.map(cpu_intensive_task, [10*<em>6] </em> 4)) </p>
注意 fork vs spawn 启动方法的兼容性陷阱
Linux 默认用 fork 启动子进程,速度快但有隐患:父进程已加载的模块(尤其含 C 扩展如 torch、cv2)可能在子进程中状态异常,导致段错误或随机崩溃。macOS 和 Windows 默认用 spawn,更安全但启动慢。
解决方式:
- 显式设置启动方法:
multiprocessing.set_start_method('spawn')放在if __name__ == '__main__':下方第一行 - 必须确保所有可执行代码都包裹在
if __name__ == '__main__':中,否则spawn会在子进程中重复导入执行,引发递归创建进程 - 某些库(如旧版 PyTorch)仍对
spawn支持不完善,需升级或查其 multiprocessing 兼容文档
别忽略数据传输开销和 NUMA 架构影响
多进程不是万能加速器。当任务本身计算量小、但参数很大(比如传一个 500MB 的 dict 给每个子进程),pickle + 反序列化时间可能远超计算时间。更隐蔽的问题是 NUMA:在多路服务器上,跨 NUMA 节点访问内存延迟高,而默认调度可能把进程分散到不同节点。
优化方向:
- 用
multiprocessing.shared_memory共享只读大数组(如numpy.ndarray),避免复制 - 用
psutil.Process().cpu_affinity()绑定进程到特定 CPU 核心组,减少跨节点访问 - 先做粗粒度基准测试:对比单进程跑 N 次 vs 多进程跑 N 次的总耗时,确认是否真有收益
真正卡住性能的,往往不是“没开多进程”,而是数据怎么给、给多少、给到哪。
Python免费学习笔记(深入):立即使用
在学习笔记中,你将探索 Python 的核心概念和高级技巧!











