gil锁住的是cpython解释器中任意时刻仅允许一个线程执行python字节码,确保引用计数等内存操作线程安全;它不锁纯c扩展代码,但python层操作(如循环、对象访问)必须持锁。

Python的GIL到底锁住了什么
GIL(Global Interpreter Lock)不是操作系统级的线程锁,而是CPython解释器内部的一把互斥锁,它确保**任意时刻只有一个线程执行Python字节码**。这意味着即使你用 threading.Thread 启了10个线程,它们在CPU密集型任务中仍会排队等待GIL,实际是串行执行。
注意:GIL不锁C扩展里的纯C代码(比如 numpy 的向量化运算),但一旦回到Python层做循环、条件判断、对象操作,就立刻受制于GIL。
为什么 threading 模块对CPU密集任务几乎没用
典型表现是:4核机器跑4个 threading.Thread 执行纯Python计算(如大列表求和、递归斐波那契),CPU使用率始终卡在25%左右,且总耗时≈单线程×1,毫无加速。
python-docx Skill功能概述python-docx Skill是一项面向实际任务的技能,主要用于本Skill提供使用python-docx生成专业Word文档的标准方法和最佳实践;生成安全服务方案文档;核心要点生成技术架构设计文档;生成任何需要专业排版的Word文档;核心库 : python-docx;使用与执行辅助库 : docx.shared , docx.enum , docx.oxml.ns;标准代码模板;1. 文档初始化;2. 字体设置(必须!它将相关步骤、工具调用和结果整理方式集
- 根本原因:每个线程执行到字节码指令前必须先抢到GIL;计算过程中不会主动让出,直到被强制中断(约每100个tick或I/O阻塞)
-
time.sleep()或input()会让出GIL,所以I/O密集型任务里threading依然有效 - 启用
threading.settrace()或调试器会显著加剧GIL争抢,进一步拖慢CPU密集场景
真正能跑满多核的替代方案
要突破GIL限制,必须绕过CPython解释器的执行路径——最直接的方式是用进程代替线程。
- 用
multiprocessing.Process或multiprocessing.Pool:每个子进程有独立的GIL和内存空间,天然支持多核并行 - 注意进程间通信开销:
Queue、Pipe、Manager都比线程共享变量慢,大数据量别频繁传对象 - 小数据+高计算量 → 优先用
multiprocessing.Pool.map() - 需要共享状态 → 考虑
multiprocessing.Value/Array(底层是mmap,无GIL) - 不想改结构?试试
concurrent.futures.ProcessPoolExecutor,API和ThreadPoolExecutor几乎一致
哪些情况你以为“没用”其实是误判
容易混淆的是“多线程没提速”不等于“多线程没运行”。常见误判点:
- 用
top看CPU%低,就以为没并行——其实可能是任务太小,启动线程+GIL切换开销 > 计算收益 - 没加
thread.join()就结束主程序,子线程被强制终止,误以为“没生效” - 用
print()测速:I/O本身会释放GIL,干扰真实计算耗时,应改用time.perf_counter()在纯计算段内测 - 第三方库已绕过GIL:比如
numpy.dot()、cv2.threshold()、requests.get()(底层是C或系统调用),它们内部会自动释放GIL
Python免费学习笔记(深入):立即使用
在学习笔记中,你将探索 Python 的核心概念和高级技巧!










