什么是 GIL?
**GIL(Global Interpreter Lock,全局解释器锁)**是 CPython 解释器里的一个"全局互斥锁",它的作用是:
同一时刻,只允许一个线程执行 Python 字节码。
哪怕你开了很多线程,在同一个进程里,也只能有一个线程真正跑 Python 代码,其他线程要排队。
典型定义: GIL 是一个互斥锁(mutex),保证任意时刻只有一个线程持有解释器执行权。
为什么会有 GIL?
核心原因:CPython 的内存管理不是线程安全的。
-
Python 对象有引用计数(ref count)
-
多线程同时修改引用计数,可能导致内存错误、崩溃
-
为了简化实现、减少锁粒度复杂度,CPython 选择了一个"大锁"------GIL
所以:
GIL 是一种"用简单换安全"的设计:实现简单、单线程性能好,但牺牲了多核并行能力。
GIL 带来的影响是什么?
1. 对单线程程序:几乎没影响,甚至有好处
-
不用担心线程安全问题
-
内存管理简单
-
单线程 CPU 利用正常
所以你平时写的脚本、Web 服务(多进程部署)基本感觉不到 GIL 的存在。
2. 对多线程 CPU 密集型 程序:影响很大(几乎不能利用多核)
比如:
-
大量计算
-
加密、压缩
-
图像处理、科学计算(纯 Python 实现)
即使你开了 8 个线程:
-
也只能有一个线程在执行 Python 字节码
-
其他线程在等 GIL
-
多线程反而有上下文切换开销
结论:CPU 密集型任务,用多线程在 CPython 里几乎没用,要用多进程或 C 扩展。
3. 对多线程 I/O 密集型 程序:影响不大,甚至还可以
比如:
-
网络请求
-
文件读写
-
数据库操作
当线程在等待 I/O 时:
-
会释放 GIL
-
其他线程可以获得 GIL 继续执行
所以:
I/O 密集型任务,多线程在 Python 里依然是有意义的。
这也是为什么:
-
requests + ThreadPool -
爬虫多线程
在 Python 里依然很好用。
面试里怎么高质量回答这道题?
你可以这样说(直接背都行):
"GIL 是 CPython 里的全局解释器锁,本质是一个互斥锁,保证同一时刻只有一个线程执行 Python 字节码。 它的好处是简化了内存管理,实现了线程安全,但代价是多线程无法真正利用多核 CPU。 对 I/O 密集型任务,多线程依然有效,因为 I/O 等待时会释放 GIL;但对 CPU 密集型任务,多线程几乎没有加速效果,一般需要用多进程或者把计算逻辑放到 C 扩展、NumPy 这类释放 GIL 的库里。"
这段话面试官听了会觉得你非常清楚地理解了 GIL 的本质和工程影响。
实战中怎么"绕开"或"减弱" GIL 的影响?
你可以顺带补一句(加分项):
-
CPU 密集型:
-
用
multiprocessing多进程 -
用 C 扩展 / NumPy / Numba(这些库内部会释放 GIL)
-
-
I/O 密集型:
-
用多线程(
threading/concurrent.futures.ThreadPoolExecutor) -
或者用异步(
asyncio/ FastAPI)
-