25 分钟
Python 高级

GIL 全局解释器锁深度

理解 GIL 的本质、影响和绕过方案

  • 理解 GIL 是什么以及为什么存在
  • 理解 GIL 对多线程性能的影响
  • 掌握绕过 GIL 的方案
  • 了解 PEP 703 无 GIL 进展

GIL 全局解释器锁深度

GIL(Global Interpreter Lock)是 Python 最著名也最容易被误解的机制。理解 GIL 是写出正确并发代码的前提。

GIL 是什么?

GIL 是 CPython 解释器里的互斥锁,同一时刻只能有一个线程执行 Python 字节码。就算用多线程,Python 代码也没法真正并行。

示例代码(可运行)
🐍资深工程师经验谈

GIL 不是 bug,是设计取舍。它让 CPython 的内存管理(引用计数)变得简单快速,C 扩展集成也更容易。代价是 CPU 密集多线程无法利用多核。注意:I/O 密集任务(网络请求、文件读写)多线程仍然有效,因为等待 I/O 时会释放 GIL。

GIL 什么时候释放?

示例代码(可运行)

绕过 GIL 的方案

示例代码(可运行)

PEP 703:无 GIL 的未来

Python 3.13 引入了实验性的 free-threaded 构建(--disable-gil),用 biased reference counting 和每对象锁替代 GIL:

示例代码(可运行)
💡选型决策

I/O 密集 → asyncio 或多线程;CPU 密集 → 多进程或 C 扩展;数据处理 → NumPy/Pandas(内部释放 GIL);别一上来就用多进程,进程间通信的序列化成本很高。

C源码

GIL 的 C 实现细节

GIL 在 CPython 中是一个条件变量 + 互斥锁:

C / C++
// CPython 源码简化
// cpython/Python/ceval_gil.c

static struct {
    PyMutex mutex;
    PyCondVar cond;
    int locked;  // GIL 是否被持有
    unsigned long interval;  // 切换间隔(us)
} gil;

void take_gil(PyThreadState *tstate) {
    // 如果 GIL 被持有,等待
    // 每隔 interval 检查 gil_drop_request
}

void drop_gil(PyThreadState *tstate) {
    // 释放 GIL,通知等待线程
}

// eval_breaker 机制:
// 每执行一定数量字节码检查是否需要释放 GIL
// 这就是 sys.setswitchinterval 控制的
选择题

为什么 Python 多线程在 CPU 密集任务中没有加速?

选择题

CPU 密集任务应该用什么方案绕过 GIL?

资深工程师加餐

底层原理 · 大厂视角 · 工程经验,点卡片展开

with 语句等价于 try/finally:无论正常结束还是中途抛异常,退出时都会执行清理(关文件、释放锁、断开连接)。实现方式有两种:类里写 __enter__/__exit__,或用 contextlib.contextmanager 把生成器变成上下文管理器。凡是「打开了必须关闭/获取了必须释放」的资源,都应该用 with 托管。

挑战任务

GIL 影响分析器

简单+50 XP

对比单线程、多线程、多进程在 CPU 密集和 I/O 密集任务上的表现差异。

GIL 影响分析器
2 个测试用例

课后作业

并发模型选择

中等+20 XP

写一个函数,根据任务类型(cpu/io)推荐并发方案。

并发模型选择
1 个测试用例