根本原因是cpython解释器的gil强制所有线程争抢同一把锁,任意时刻仅一个线程执行python字节码;io操作会主动释放gil,但纯计算任务中gil锁死导致多核无法并行。

Python多线程在多核CPU上跑不满负载,根本原因不是线程没调度、不是系统不支持、也不是代码写错了——而是CPython解释器强制让所有线程争抢同一把锁:GIL。哪怕你启了16个线程跑在16核机器上,任意时刻最多只有1个线程在执行Python字节码。
为什么threading启动多个线程后CPU使用率仍卡在10%–30%
这不是资源没分配到,是GIL在“主动限速”:CPython默认每执行约100条字节码就释放一次GIL,然后轮到下一个线程抢锁。整个过程本质是单核串行模拟并发,线程越多,上下文切换开销越大,实际吞吐可能比单线程还低。
- 现象:用
top或htop观察,所有Python线程都集中在同一个CPU核心上跑(%CPU高但%CPU0爆满、其他核空闲) - 验证方式:运行两个死循环线程
while True: pass,你会发现总CPU占用≈单核100%,而非双核200% - 关键点:
GIL是进程级的,不是线程级的——一个Python进程只有一个GIL,所有线程共享它
multiprocessing为何能真正打满多核
因为每个子进程都有自己的Python解释器实例和独立的GIL。操作系统把它们分发到不同核心上,互不干扰,自然能实现物理并行。
- 示例中用
multiprocessing.cpu_count()启动N个Process,每个都能独占1个逻辑核 - 注意:进程间数据不共享,传参需序列化(
pickle),大对象传递有开销 - 不要混用
threading和multiprocessing处理同一计算任务——线程部分仍受GIL拖累,白加一层调度
Python 3.12+的interpreters模块是不是新出路
是,但有硬限制:子解释器目前不能安全共享可变Python对象(如list、dict),且run_async只接受纯函数+不可变参数。它绕开了GIL,但不是“升级版线程”,而是轻量级隔离环境。
- 适用场景:状态无关的计算单元(比如图像分块处理、独立模型推理)
- 不适用场景:需要频繁读写同一全局缓存、或依赖
import副作用的逻辑 - 当前稳定度:API仍标记为
provisional,生产环境慎用;调试工具链(如pdb)支持弱
真正容易被忽略的一点:GIL释放时机不只看时间片,更取决于操作类型——time.sleep()、socket.recv()、open().read()等IO调用会主动让出GIL,所以IO密集型任务用threading反而高效;但只要代码里出现连续数学运算、字符串拼接、列表推导这类纯Python计算,GIL就锁死,多核等于摆设。
Python免费学习笔记(深入):立即使用
在学习笔记中,你将探索 Python 的核心概念和高级技巧!











