菜单

运行时与线程管理

相关源文件

此页面记录了 CPython 的运行时和线程管理系统,该系统负责管理全局运行时状态、解释器实例、线程状态以及全局解释器锁 (GIL) 等并发控制机制。有关内存管理和对象分配的信息,请参阅对象系统和内存管理

概述

Python 运行时系统由几个分层组件组成,它们协同工作以管理解释器的执行环境。

运行时系统管理着

  1. 全局运行时状态:维护所有解释器共享的全局信息。
  2. 解释器实例:每个解释器都有自己的全局状态和模块。
  3. 线程状态:跟踪每个操作系统线程的执行状态。
  4. GIL 管理:控制线程对 Python 解释器的访问。
  5. 线程创建和销毁:处理线程的生命周期。

Sources: Python/pystate.c Python/pylifecycle.c Include/internal/pycore_runtime.h Include/internal/pycore_interp.h

运行时状态

全局运行时状态由 _PyRuntimeState 结构表示,这是一个单例,在 Python 进程的整个生命周期中都存在。它包含进程范围的信息,并作为解释器状态层次结构的根。

关键组件和字段

  • 初始化标志:跟踪 Python 是否已初始化(initializedcore_initialized)。
  • 解释器列表:跟踪所有解释器实例(interpreters.head)。
  • 主解释器:对主解释器的直接引用(main_interpreter)。
  • 主线程 ID:主解释器的主线程 ID(main_thread)。
  • 线程局部存储:线程状态存储的键(autoTSSkey)。
  • GIL 状态:全局解释器锁数据(gil)。

运行时通过 _PyRuntimeState_Init() 初始化,并通过 _PyRuntimeState_Fini() 销毁。在初始化期间,会创建线程局部存储键并初始化各种子系统。

Sources: Python/pystate.c446-486 Python/pystate.c489-503 Include/internal/pycore_runtime_init.h39-121

解释器状态

每个 Python 解释器实例由一个 PyInterpreterState 结构表示。单个进程可以共存多个解释器,每个解释器都有自己的全局状态。创建的第一个解释器是“主解释器”。

关键属性和职责

  • 运行时引用:指向全局运行时(runtime)。
  • 解释器 ID:唯一标识符(id)。
  • 线程列表:此解释器中所有线程的链表指针(prev, next)。
  • 模块状态:已加载模块的字典(modules)。
  • 内置对象:内置函数和对象的字典(builtins)。
  • 系统状态sys 模块的字典(sysdict)。
  • 功能标志:运行时功能能力(feature_flags)。
  • GC 状态:此解释器的垃圾收集器状态(gc)。
  • 评估状态:代码评估和 GIL 状态(ceval)。

解释器使用 PyInterpreterState_New() 创建,并使用 PyInterpreterState_Clear() 后跟 PyInterpreterState_Delete() 销毁。

Sources: Python/pystate.c707-788 Python/pystate.c812-958 Include/internal/pycore_interp.h76-97

线程状态

执行 Python 代码的每个操作系统线程都由一个 PyThreadState 结构表示。此结构维护解释器所需的线程特定执行状态。

关键组件

  • 解释器引用:指向其所属的解释器(interp)。
  • 线程列表:线程注册表的链表指针(prev, next)。
  • GIL 状态:指示该线程是否持有 GIL 的标志(holds_gil)。
  • 线程状态:当前执行状态(state - 已附加、已分离或已挂起)。
  • 评估中断器:用于中断执行的标志(eval_breaker)。
  • 异常状态:当前正在处理的异常(exc_value)。
  • 执行帧:当前正在执行的 Python 帧(current_frame)。
  • 递归控制:递归深度的限制(py_recursion_remaining, py_recursion_limit)。
  • 跟踪状态:用于性能分析和调试(tracing, c_tracefunc, c_profilefunc)。
  • 状态标志:内部线程状态标志(_status)。

线程状态转换遵循此生命周期。

线程状态也管理着线程局部数据所使用的线程特定存储变量。

Sources: Python/pystate.c250-301 Include/cpython/pystate.h66-265 Python/pystate.c147-178

全局解释器锁 (GIL)

全局解释器锁 (GIL) 是一个互斥锁,可防止多个线程在同一解释器内同时执行 Python 字节码。它是 CPython 并发模型的一个基本方面。

GIL 实现包含以下关键组件:

  1. GIL 状态:一个受互斥锁保护的标志,指示 GIL 是否已被持有(gil->locked)。
  2. GIL 互斥锁:一个系统互斥锁,用于保护对 GIL 状态的访问(gil->mutex)。
  3. GIL 条件变量:用于向等待 GIL 的线程发出信号(gil->cond)。
  4. 切换间隔:控制一个线程可以持有 GIL 多长时间,之后其他线程才有机会(gil->interval,可通过 sys.setswitchinterval() 配置)。

GIL 操作包括:

  • 获取:通过 take_gil(),它会等待 GIL 可用,然后获取它。
  • 释放:通过 drop_gil(),它会释放 GIL 并通知等待的线程。
  • 强制切换:评估循环会定期检查是否有其他线程需要 GIL,并在请求时释放它。

GIL 确保了 Python 内存管理和引用计数的线程安全,但代价是无法实现真正的 Python 代码并行执行。

Sources: Python/ceval_gil.c52-275 Python/ceval_gil.c278-460

自由线程模式(Python 3.13+)

Python 3.13 引入了一个实验性的“自由线程”模式,该模式允许 Python 在没有 GIL 的情况下运行,从而实现 Python 代码在多个核心上的真正并行执行。

自由线程模式的关键方面

  1. 构建时选项:需要使用 --disable-gil 编译 Python。
  2. 运行时控制:可以通过 PYTHON_GIL 环境变量或 X gil=0/1 选项在运行时启用/禁用。
  3. 扩展兼容性:C 扩展必须明确表明支持自由线程。
  4. 性能:单线程性能有所下降,但并行执行可以提供整体加速。
  5. 线程同步:使用原子操作和细粒度锁,而不是 GIL。

在自由线程模式下,线程安全通过原子引用计数和每个对象的锁来保证。C 扩展需要进行调整以支持此模式,导入不兼容的扩展将自动启用 GIL。

来源: Doc/whatsnew/3.13.rst102-115 Python/ceval_gil.c227-274 Include/object.h147-163

线程管理 API

CPython 提供了多个用于创建和管理线程状态的 API

线程状态的创建和管理

关键的线程管理函数

  1. 线程状态创建:

    • PyThreadState_New():为给定的解释器创建一个新的线程状态
    • _PyThreadState_Bind():将线程状态绑定到当前的操作系统线程
  2. 线程状态激活:

    • PyThreadState_Swap():使一个线程状态成为当前线程状态
    • _PyThreadState_GET():获取当前线程状态(内部使用)
  3. GIL 管理:

    • _PyEval_AcquireLock():为线程获取 GIL
    • _PyEval_ReleaseLock():释放 GIL
  4. 线程状态终结:

    • PyThreadState_Clear():清除线程状态的数据
    • PyThreadState_Delete():释放线程状态
  5. 线程状态挂起 (用于无 GIL 模式)

    • _PyThreadState_Suspend():挂起一个线程(将其置于挂起状态)
    • _PyThreadState_Resume():恢复一个被挂起的线程

这些 API 主要由 threading 模块和需要创建或管理线程的 C 扩展使用。

来源: Python/pystate.c615-704 Python/ceval_gil.c284-378

解释器与 sys 模块的交互

sys 模块为 Python 代码提供了对某些运行时和线程状态信息及控制的访问权限

与运行时和线程相关的关键 sys 模块功能

  1. GIL 控制:

    • sys.getswitchinterval():获取 GIL 切换间隔
    • sys.setswitchinterval():设置 GIL 切换间隔
  2. 线程信息:

    • sys._current_frames():获取所有线程的当前帧对象
    • sys._current_exceptions():获取所有线程的当前异常
  3. 无锁线程信息:

    • sys._is_gil_enabled():检查 GIL 是否启用(3.13 新增)

这些 API 允许 Python 代码与运行时和线程管理系统进行交互和观察。

来源: Python/sysmodule.c79-145 Python/sysmodule.c148-212 Doc/library/sys.rst1-167

线程状态绑定和线程本地存储

CPython 使用线程本地存储 (TLS) 将线程状态与操作系统线程关联起来

存在两种线程状态存储

  1. 快速当前线程状态:用于当前持有 GIL 的线程,通过 _PyThreadState_GET() 访问
  2. 线程特定存储:将 OS 线程与其线程状态链接起来,通过 gilstate_tss_get()gilstate_tss_set() 管理

线程绑定操作

  • bind_tstate():将线程状态与当前 OS 线程关联
  • unbind_tstate():将线程状态与其 OS 线程解除关联
  • bind_gilstate_tstate():为 GIL 状态 API 使用绑定线程状态

这些机制确保线程状态与 OS 线程正确关联,并可以从代码的任何位置正确访问。

来源: Python/pystate.c124-165 Python/pystate.c249-301 Python/pystate.c320-354