python多线程在cpu密集任务中不提速,根本原因是cpython的gil强制同一时刻仅一个线程执行字节码;io密集任务中因gil自动释放仍高效;突破gil首选多进程,其次协程或c扩展。

Python 的 threading 模块在 CPU 密集任务中基本不提速,根本原因就是 CPython 解释器强制只允许一个线程执行 Python 字节码——这不是 bug,是设计选择。
为什么 GIL 锁的是解释器,不是你的代码
GIL 不管你写的是 for 循环、list.append() 还是自定义类方法,它锁住的是整个 CPython 解释器的运行时状态。只要代码走的是纯 Python 路径(即被编译成字节码并由解释器执行),就绕不开它。
- 它保护的是
ob_refcnt(引用计数)等底层内存管理字段,防止多线程同时增减导致崩溃 - 它不保护你自己的变量或逻辑——所以你仍需用
threading.Lock保护共享数据 - 调用 C 扩展(如
numpy.dot()、cv2.imread())时,这些函数内部会主动释放 GIL,此时其他 Python 线程才能抢到执行权
threading 在什么场景下真有用
不是所有多线程都白忙——关键看线程是否频繁让出 GIL。
SkillSub Pro - Python 题解与代码注释双功能技能功能概述SkillSub Pro - Python 题解与代码注释双功能技能是一项面向实际任务的技能,主要用于SkillSub Pro 是一个 Python 题解生成与代码注释的 双功能合体技能 ,专为学生、算法学习者和开发者设计;✅ 一个技能,两种用途 :;核心要点📝 题解模式 :输入题目/题号,自动生成完整 Python 题解(含详细注释、解题思路、复杂度分析);💬 注释模式 :输入 Python 代码,自动添加详细中。它将相关步骤、
- IO 密集型:比如发 HTTP 请求(
requests.get())、读文件(f.read())、数据库查询(cursor.execute()),这些操作底层会触发系统调用,自动释放 GIL,其他线程立刻可运行 - 混合任务:主线程做少量计算 + 多个线程并发发请求,整体吞吐明显提升
- 注意陷阱:
time.sleep()会释放 GIL,但while True: pass不会,后者会死占着锁,把其他线程饿死
为什么 multiprocessing 是更直接的替代方案
multiprocessing 绕过 GIL 的方式很粗暴:每个子进程启动独立的 CPython 解释器实例,各自带一把 GIL。
- 开 4 个
Process,就能跑满 4 核 CPU(前提是你有足够计算量) - 代价是进程启动开销大、内存复制成本高(
fork或spawn)、IPC(进程间通信)比线程间共享变量麻烦得多 - 推荐组合:
concurrent.futures.ProcessPoolExecutor比裸写multiprocessing.Process更易用,且能统一异常处理
别指望靠 threading.Thread 靠数量堆性能
加到 100 个 Thread 对 CPU 密集任务毫无帮助,反而可能更慢。
- 线程切换本身要消耗时间,GIL 抢占失败还会触发内核态调度,开销不小
- CPython 3.2+ 虽优化了 GIL 切换策略(避免“饿死”),但没改变“同一时刻仅一核干活”的本质
- 真正需要并行计算时,优先考虑:
multiprocessing、numba.jit(带nogil=True)、或把瓶颈部分用 Cython/C 写并显式释放 GIL
真正容易被忽略的点是:GIL 的存在让你无法靠增加线程数来横向扩展 CPU 计算能力——它不是配置问题,也不是代码写得不够好,而是解释器层面的硬约束。想提速,得换执行模型,而不是换写法。
Python免费学习笔记(深入):立即使用
在学习笔记中,你将探索 Python 的核心概念和高级技巧!










