python 3.12 默认gil行为与3.11完全一致,threading、threadpoolexecutor、asyncio性能无自动变化;所谓“变快/变慢”多因time.time()抖动、冷启动偏差、i/o释放时机优化或误用--disable-gil编译版所致。

Python 3.12 的 GIL 并没有“更改”导致测试性能变化——它默认行为和 3.11 完全一致,threading、concurrent.futures.ThreadPoolExecutor、asyncio 的表现不会自动变快或变慢。所谓“性能变化”,几乎全是误判或配置错位的结果。
为什么你的测试跑出“变慢/变快”了?
真实原因往往与 GIL 无关,而是以下几类干扰项被当成了 GIL 效应:
-
time.time()在高精度场景下受系统调度抖动影响更大,尤其在短任务中;建议改用time.perf_counter() - Python 3.12 默认启用了更快的 tokenizer 和更激进的字节码缓存,但首次导入模块可能略慢(冷启动偏差),连续多次运行才反映真实吞吐
- 你用的测试代码本身含 I/O 或 sleep,而 Python 3.12 的“自适应 GIL”策略会更早释放锁给等待线程——这会让 I/O 密集型任务看起来“更公平”,但不是“更快”
- 如果你在 CI 环境中跑测试,且用了
--disable-gil编译的 Python(极罕见),那必须显式加-X gil=on才能复现旧行为;否则就是拿无 GIL 运行时跟有 GIL 基线比,结果毫无可比性
如何做真正有效的 GIL 影响对比
要验证 GIL 相关变化是否生效,必须控制变量、绕过干扰:
- 用
python -X dev -X gil=off启动(仅限已编译--disable-gil的 Python),再运行纯 CPU 密集任务,如sum(i * i for i in range(5_000_000)) - 禁用所有非必要扩展:启动时加
-S参数跳过 site 模块,避免第三方包干扰 - 固定线程数并绑定到物理核:
taskset -c 0-3 python test.py,排除 NUMA 或调度器偏移 - 对比指标不是单次耗时,而是 4 线程总吞吐(例如每秒完成的任务数),因为 GIL 优化目标是提升并发利用率,不是降低单任务延迟
哪些测试根本不需要碰 GIL 配置
绝大多数项目测试完全不受 GIL 变动影响,包括:
- 单元测试(
unittest、pytest)——它们本质是顺序执行,不依赖多线程加速 - 异步测试(
asyncio.run()+await)——GIL 对协程调度无直接影响 - IO 密集型集成测试(HTTP 请求、DB 查询)——GIL 本就会在系统调用时释放,3.12 只是让释放时机更稳,不改变正确性
- 使用
multiprocessing的测试——进程间天然无 GIL 共享,和解释器版本无关
真正容易被忽略的是:你在本地开发机上看到的“性能差异”,大概率来自 pip install 升级了某个依赖(比如 numpy 从 1.25 升到 2.0,底层 BLAS 切换),而不是 Python 解释器本身的 GIL 行为变了。先查 pip list --outdated,再谈 GIL。
Python免费学习笔记(深入):立即使用
在学习笔记中,你将探索 Python 的核心概念和高级技巧!











