lang
lang/python/data-model/gil-and-free-threading.md
high
py-gil-and-free-threading
GIL 让 CPython 同一时刻只跑一个线程的字节码,故多线程不加速 CPU 密集;3.13/3.14 free-threading(PEP 703/779) 可关 GIL。Use when 多线程跑满 CPU 却不提速 / 选并发模型 / 评估 no-GIL 构建。
gil全局解释器锁free-threading自由线程pep 703
paths
*.pypy/**/*.py
Python · GIL 与 free-threading
规则
| 工作负载 | 标准 CPython(带 GIL) | 该用什么 |
|---|---|---|
| CPU 密集(算数 / 解析 / 压缩) | 多线程不提速:GIL 让字节码串行执行 | multiprocessing / ProcessPoolExecutor,或 free-threading 构建 |
| I/O 密集(网络 / 磁盘 / DB) | 多线程有效:阻塞时释放 GIL | threading / asyncio |
| 调 C 扩展(numpy / 压缩库) | 计算段常释放 GIL,可并行 | 多线程即可 |
核心:GIL 是 CPython 实现的一把进程级互斥锁,同一时刻只有一个线程执行 Python 字节码。 它简化了内存管理,但使纯 Python 的 CPU 密集多线程退化为串行 + 切换开销。
free-threading(PEP 703 / 779,3.13 起)
3.13 引入实验性 free-threaded 构建(python3.13t),可在运行时关闭 GIL
3.14 PEP 779:free-threading 从实验转为“官方支持”阶段(仍非默认)
代价 单线程性能有约 5-10% 损耗;默认解释器仍带 GIL
检测 python -VV 看是否 free-threading;运行期 sys._is_gil_enabled()
正例
from concurrent.futures import ProcessPoolExecutor
def cpu_heavy(n: int) -> int:
return sum(i * i for i in range(n)) # 纯 Python CPU 密集
# ✅ 标准 CPython 下,CPU 密集靠多进程绕开 GIL
with ProcessPoolExecutor() as pool:
results = list(pool.map(cpu_heavy, [10_000_000] * 8))
import sys
# 探测当前解释器是否真的关掉了 GIL(free-threaded 构建才有此函数)
if hasattr(sys, "_is_gil_enabled") and not sys._is_gil_enabled():
from concurrent.futures import ThreadPoolExecutor # 此时线程可真正并行 CPU
反例
# ❌ 标准 CPython 下用线程跑 CPU 密集,期望多核加速
from concurrent.futures import ThreadPoolExecutor
with ThreadPoolExecutor(max_workers=8) as pool:
pool.map(cpu_heavy, [10_000_000] * 8) # 8 核机器上几乎不比单线程快
理由:GIL 保证同一时刻仅一个线程跑字节码,纯计算线程拿不到并行,反而多了锁竞争与上下文切换。CPU 密集要么多进程、要么用 free-threading 构建(确认 GIL 已关)。
自检
- [ ] CPU 密集用多进程 / free-threading,没指望标准 CPython 的多线程加速?
- [ ] I/O 密集才用
threading/asyncio? - [ ] 用 free-threading 前确认了
python -VV/sys._is_gil_enabled(),并接受单线程 5-10% 损耗? - [ ] 依赖的 C 扩展声明了 free-threading 兼容,避免在无 GIL 下竞态?
相关
- 父:
./index.md - 兄弟:
copy-semantics.md(多进程间对象需序列化拷贝) ·is-vs-equals.md