菜单

代码执行流程

相关源文件

本文档全面概述了 CPython 的代码执行管道——Python 源代码被转换为可执行指令并随后执行的过程。该管道包括解析、编译、优化和执行阶段,这些阶段协同工作以高效地运行 Python 程序。

有关管道特定阶段的实现细节,请参阅 编译管道字节码解释器与优化

高层概览

CPython 代码执行管道包含多个阶段,可将 Python 源代码转换为运行的软件

来源: Python/compile.c1-14 Python/ceval.c1-47 Python/bytecodes.c1-41 Python/optimizer.c1-22

编译管道

编译阶段通过一系列明确定义的步骤将 Python 源代码转换为字节码

来源: Python/compile.c107-148 Python/flowgraph.c75-106 Python/symtable.c1-34

符号表生成 (Symbol Table Generation)

在代码生成之前,会创建一个符号表来跟踪变量及其作用域。此分析有助于确定哪些名称是局部、全局、非局部或闭包变量

来源: Python/symtable.c91-108 Python/compile.c138-146

代码生成

代码生成阶段将 AST 转换为中间指令序列

  1. 从 AST 生成指令序列
  2. 基本块被组合成控制流图
  3. 优化应用于控制流图
  4. 优化后的图被组装成最终的字节码

来源: Python/compile.c1-17 Python/codegen.c1-10 Python/flowgraph.c66-87 Python/assemble.c1-5

字节码解释器 (Bytecode Interpreter)

字节码格式 (Bytecode Format)

Python 字节码由虚拟机执行的操作(操作码)和参数(操作数)组成

组件描述
co_code字节码指令序列(每条 2 字节)
co_consts代码中使用的常量元组
co_names代码中引用的名称元组
co_varnames局部变量名元组
co_freevars自由变量名元组
co_cellvars单元变量名元组

来源: Python/compile.c461-468

分层执行架构 (Tiered Execution Architecture)

CPython 使用分层执行模型

来源: Python/bytecodes.c76-146 Python/generated_cases.c.h1-30 Python/ceval.c500-535 Python/optimizer.c100-154

Tier 1:字节码解释器

基线解释器直接执行字节码指令。它通过 _PyEval_EvalFrameDefault 函数运行,该函数在一个循环中处理每个指令

  1. 获取下一条指令
  2. 解码操作码和操作数
  3. 执行指令
  4. 更新解释器状态

字节码指令在 bytecodes.c 中使用结构化格式定义,并经过处理以生成解释器 switch case

inst(LOAD_FAST, (-- value)) {
    assert(!PyStackRef_IsNull(GETLOCAL(oparg)));
    value = PyStackRef_DUP(GETLOCAL(oparg));
}

来源: Python/bytecodes.c268-277 Python/generated_cases.c.h21-81 Python/ceval.c30-46

专业化与优化 (Specialization and Optimization)

CPython 采用各种专业化技术来优化执行

专业化类型示例
基于类型BINARY_OP_ADD_INT 用于整数加法
基于值LOAD_CONST_IMMORTAL 用于不朽对象
基于形状LOAD_ATTR_INSTANCE_VALUE 用于直接实例属性访问

来源: Python/bytecodes.c583-621 Python/bytecodes.c295-333

Tier 2:基于跟踪的优化器

Tier 2 执行系统使用基于跟踪的优化来提高性能

来源: Python/optimizer.c100-154 Python/executor_cases.c.h1-74 Include/internal/pycore_uop_ids.h1-20

微操作 (UOps)

优化器将字节码指令分解为更小的微操作 (UOps),它们代表更细粒度的操作

  1. 原始字节码被转换为 UOps
  2. UOps 允许更精确的分析和优化
  3. 多个优化应用于 UOp 序列
  4. 优化后的序列被打包成 Executor 对象

例如,BINARY_OP 指令可以分解为像 _BINARY_OP_ADD_INT 这样的专用 UOps

case _BINARY_OP_ADD_INT: {
    PyObject *left_o = PyStackRef_AsPyObjectBorrow(left);
    PyObject *right_o = PyStackRef_AsPyObjectBorrow(right);
    assert(PyLong_CheckExact(left_o));
    assert(PyLong_CheckExact(right_o));
    
    STAT_INC(BINARY_OP, hit);
    PyObject *res_o = _PyLong_Add((PyLongObject *)left_o, (PyLongObject *)right_o);
    PyStackRef_CLOSE_SPECIALIZED(right, _PyLong_ExactDealloc);
    PyStackRef_CLOSE_SPECIALIZED(left, _PyLong_ExactDealloc);
    // ...
}

来源: Python/executor_cases.c.h175-199 Python/bytecodes.c626-664

数据流分析与优化

Tier 2 优化器执行数据流分析,以跟踪跟踪中的变量值和类型

  1. 类型分析:推断并传播类型信息
  2. 常量传播:用已知的常量值替换变量
  3. 死代码消除:删除无效果的代码
  4. Guard 生成:插入 Guard 以验证运行时假设

来源: Python/optimizer_analysis.c1-32 Python/optimizer_cases.c.h106-157

Guard 指令和去优化

Guard 是特殊指令,用于验证优化过程中所做的假设

来源: Python/optimizer_cases.c.h107-148 Python/optimizer_bytecodes.c107-142

实验性即时编译

在 Python 3.13+ 中,正在开发一项实验性的即时(Just-In-Time)编译器,用于将优化后的跟踪转换为本地机器码

  1. 热跟踪由 Tier 2 优化器识别
  2. 对跟踪进行分析和优化
  3. 为优化后的跟踪生成机器码
  4. 执行跳转到带有适当 Guard 的本地代码

来源: Python/optimizer.c213-215

插桩和监控

字节码执行流水线支持用于调试、分析和监控的插桩

来源: Python/instrumentation.c1-32 Python/instrumentation.c74-107

整合

CPython 代码执行流水线是一个复杂的系统,通过多个编译和优化阶段将 Python 源代码转换为运行中的程序。通过使用具有专用指令的分层执行方法、基于跟踪的优化以及潜在的 JIT 编译,CPython 能够高效地执行 Python 代码,同时保持语言的灵活性和动态性。

了解此流水线有助于开发人员优化其 Python 代码,并通过针对执行堆栈的适当层进行改进来为 CPython 本身做出贡献。