Python 3.11 在特定场景下比 3.10 快约 40%,仅对 CALL、LOAD_ATTR、LOAD_GLOBAL、BINARY_SUBSCR 四类高频字节码做运行时特化,依赖单进程内线程独立的 adaptive_state 统计,需类型稳定、高频执行且进程寿命足够长;字符串拼接因移除就地优化可能变慢。

Python 3.11 的执行速度在特定场景下比 Python 3.10 提升约 40%,不是因为整体“变快了”,而是解释器对几类高频字节码做了运行时特化(specialization),只在类型稳定、反复执行的热点路径上生效。
特化只对这几条字节码起作用
不是所有代码都提速,CALL、LOAD_ATTR、LOAD_GLOBAL、BINARY_SUBSCR 这四类指令占 Python 程序执行时间的大头,3.11 对它们动态生成专用路径:
-
LOAD_ATTR:连续访问同一类对象的同名属性(如obj.name总是返回str)时,跳过类型检查和属性查找缓存布局 -
CALL:函数调用若参数类型稳定(如总是传int),会内联简单逻辑、减少帧对象开销 -
BINARY_SUBSCR:对list[i]或dict[k]连续访问且键/索引类型一致时,避免通用哈希或边界检查 - 特化失败时自动退回到 3.10 的通用路径,无额外开销
adaptive_state 是关键,但它不跨进程也不跨线程
特化依赖解释器内部的 adaptive_state 统计——记录某条字节码被执行次数、参数类型分布、异常抛出位置等。这个状态:
- 仅存在于单个进程生命周期内,容器重启后清空
- 每个线程维护独立副本,
FastAPI + Uvicorn多 worker 模式下,每个 worker 需单独“学习”热点 - 用
fork()启动的子进程(如 Gunicorn prefork)能继承父进程已积累的部分缓存 - 短命进程(如 AWS Lambda 单次运行)几乎无法触发特化,
adaptive_state来不及累积就退出
字符串拼接反而可能更慢
你看到的性能下降(比如 a += 'x' 从 146ms 涨到 15s),根本原因不是特化失效,而是 3.11 移除了该操作的就地优化:
- 统一走
PyUnicode_Concat路径,未适配新特化机制 - 长字符串重复拼接退化为
O(n²)时间复杂度 - 这不是 bug,是权衡:优先保障
CALL和LOAD_ATTR这类更通用瓶颈的优化 - 改用
''.join(list_of_strings)可规避此问题


















