GIL 性能瓶颈排查
问题
Python GIL 在什么场景下会成为性能瓶颈?如何排查和解决?
答案
GIL 瓶颈场景
验证 GIL 瓶颈
debug/gil_test.py
import time
import threading
import multiprocessing
def cpu_intensive(n: int) -> int:
"""CPU 密集任务"""
total = 0
for i in range(n):
total += i * i
return total
N = 10_000_000
# 单线程
start = time.perf_counter()
cpu_intensive(N)
cpu_intensive(N)
print(f"单线程: {time.perf_counter() - start:.2f}s")
# 多线程(受 GIL 限制,不会更快)
start = time.perf_counter()
t1 = threading.Thread(target=cpu_intensive, args=(N,))
t2 = threading.Thread(target=cpu_intensive, args=(N,))
t1.start(); t2.start()
t1.join(); t2.join()
print(f"多线程: {time.perf_counter() - start:.2f}s") # 几乎和单线程一样
# 多进程(绕过 GIL)
start = time.perf_counter()
with multiprocessing.Pool(2) as pool:
pool.map(cpu_intensive, [N, N])
print(f"多进程: {time.perf_counter() - start:.2f}s") # 约一半时间
解决方案
solutions/numba_example.py
# 方案 1:Numba JIT 编译(释放 GIL)
from numba import jit, prange
@jit(nopython=True, nogil=True, parallel=True)
def parallel_sum(n: int) -> int:
total = 0
for i in prange(n):
total += i * i
return total
solutions/c_extension.py
# 方案 2:C 扩展(numpy 内部释放 GIL)
import numpy as np
def numpy_sum(n: int) -> float:
arr = np.arange(n, dtype=np.float64)
return np.sum(arr * arr) # C 层面并行,不受 GIL
solutions/multiprocess.py
# 方案 3:multiprocessing + 共享内存
from multiprocessing import Pool, shared_memory
import numpy as np
def worker(shm_name: str, shape: tuple, start: int, end: int) -> float:
shm = shared_memory.SharedMemory(name=shm_name)
arr = np.ndarray(shape, dtype=np.float64, buffer=shm.buf)
return float(np.sum(arr[start:end] ** 2))
用 py-spy 定位 GIL 竞争
# 安装
pip install py-spy
# 火焰图
py-spy record -o profile.svg --pid <PID>
# GIL 分析
py-spy dump --pid <PID> --gil
常见面试问题
Q1: GIL 什么时候会释放?
答案:
- IO 操作:文件读写、网络请求自动释放
- C 扩展:NumPy、Pillow 等在 C 代码中手动释放
- 定时释放:每执行一定字节码后释放(Python 3.2+ 每 5ms)
time.sleep():主动释放
Q2: Python 3.13 的 Free-threaded 模式?
答案:
Python 3.13 引入实验性的无 GIL 模式(PEP 703):
python3.13t编译时去掉 GIL- 多线程可以真正并行执行 CPU 密集任务
- 但目前兼容性不足,C 扩展需要适配
Q3: 什么时候用多线程 vs 多进程 vs asyncio?
答案:
| 场景 | 推荐方案 |
|---|---|
| CPU 密集计算 | multiprocessing / Numba |
| IO 密集(网络请求) | asyncio |
| IO 密集(文件/数据库) | threading / asyncio |
| 混合型 | 多进程 + 进程内 asyncio |