python多线程在cpu密集型任务中变慢,根本原因是gil强制所有线程串行执行python字节码;即使多核多线程,也仅一个线程真运行,其余空转争锁,线程切换开销反致耗时比单线程多10%–30%。

Python的全局解释器锁(GIL)会显著拖慢多线程在CPU密集型任务中的表现,根本原因不是“线程写得不对”,而是CPython解释器强制所有Python字节码串行执行——哪怕你开了8个线程、跑在32核服务器上,也只有一条线程真正在干活。
为什么threading在计算任务里反而更慢?
这不是bug,是GIL的必然结果:
-
threading线程启动后,每个都试图抢GIL来执行循环或算术运算;但同一时刻只能有一个成功,其余线程在原地空转等待 - 操作系统仍会按时间片强制切换线程,每次切换都要保存寄存器、刷新缓存、重新申请
GIL——这些全是纯开销 - 实测常见场景:两个
threading.Thread跑相同规模的sum(i**2 for i in range(10**7)),总耗时比单线程多10%~30%
time.sleep()和requests.get()为啥不卡?
因为它们触发了GIL的主动释放机制:
- 当线程调用系统级I/O函数(如
read()、recv()、sleep())时,CPython会自动释放GIL - 此时其他线程能立刻拿到锁并执行,形成“伪并行”——看起来快,实际仍是单核跑Python逻辑
- 所以
threading适合爬虫、日志轮转、数据库连接池等大量等待的场景,不适合图像缩放、加密解密、数值模拟
绕过GIL的三个真实可行路径
别再纠结“怎么让threading变快”,直接换执行模型:
- 用
multiprocessing:每个子进程有独立的解释器和GIL,天然绕过限制;代价是进程间通信开销大、内存占用翻倍 - 调用释放GIL的C扩展:比如
numpy.dot()、cv2.cvtColor()内部会临时放开GIL,纯Python循环外包给C代码 - 改用
asyncio+await:虽然不解决CPU瓶颈,但在高并发I/O中比threading内存更省、调度更可控
真正容易被忽略的是:GIL不是Python语言规范,而是CPython实现的约束。PyPy、Jython、以及刚进入beta测试的CPython 3.13 --nogil模式,都在尝试移除它——但目前生产环境唯一稳态解,仍是把CPU密集逻辑从threading里拎出来,交给multiprocessing或C扩展处理。
Python免费学习笔记(深入):立即使用
在学习笔记中,你将探索 Python 的核心概念和高级技巧!











