Python 自由线程实验性支持¶
从 3.13 版本开始,CPython 对一种称为自由线程的 Python 构建版本提供了实验性支持,该版本禁用了全局解释器锁 (GIL)。自由线程执行允许通过在可用 CPU 核心上并行运行线程来充分利用可用的处理能力。虽然并非所有软件都能自动从中受益,但考虑到线程设计的程序将在多核硬件上运行得更快。
自由线程模式是实验性的,并且正在进行改进工作:请预期一些错误以及单线程性能的显著下降。
本文档描述了自由线程对 Python 代码的影响。有关如何编写支持自由线程构建的 C 扩展的信息,请参阅自由线程的 C API 扩展支持。
另请参阅
PEP 703 – 使 CPython 中的全局解释器锁成为可选,其中对自由线程 Python 进行了总体描述。
安装¶
从 Python 3.13 开始,官方 macOS 和 Windows 安装程序可选地支持安装自由线程 Python 二进制文件。安装程序可在https://pythonlang.cn/downloads/上找到。
有关其他平台的信息,请参阅安装自由线程 Python,这是一个由社区维护的安装自由线程 Python 的指南。
从源代码构建 CPython 时,应使用--disable-gil
配置选项来构建自由线程 Python 解释器。
识别自由线程 Python¶
要检查当前解释器是否支持自由线程,python -VV
和sys.version
包含“experimental free-threading build”。新的sys._is_gil_enabled()
函数可用于检查正在运行的进程中是否实际禁用了 GIL。
sysconfig.get_config_var("Py_GIL_DISABLED")
配置变量可用于确定构建是否支持自由线程。如果变量设置为1
,则构建支持自由线程。这是与构建配置相关的决策的推荐机制。
自由线程 Python 中的全局解释器锁¶
CPython 的自由线程构建支持在运行时使用环境变量PYTHON_GIL
或命令行选项-X gil
选择启用 GIL。
当导入未显式标记为支持自由线程的 C-API 扩展模块时,GIL 也可能会自动启用。在这种情况下,将打印警告。
除了各个软件包的文档之外,以下网站还跟踪受欢迎的软件包对自由线程的支持状态
线程安全¶
CPython 的自由线程构建旨在在 Python 级别提供与默认启用 GIL 的构建类似的线程安全行为。诸如dict
、list
和set
之类的内置类型使用内部锁来防止并发修改,其行为方式与 GIL 类似。但是,Python 历来没有保证对这些内置类型的并发修改的特定行为,因此这应被视为当前实现的描述,而不是对当前或未来行为的保证。
注意
建议尽可能使用threading.Lock
或其他同步原语,而不是依赖内置类型的内部锁。
已知限制¶
本节描述了自由线程 CPython 构建的已知限制。
永生化¶
3.13 版本的自由线程构建使一些对象永生化。永生对象不会被解除分配,并且其引用计数永远不会被修改。这样做是为了避免引用计数争用,而这会阻止高效的多线程扩展。
在主线程运行后第一次启动新线程时,对象将被永生化。以下对象将被永生化
由于永生对象永远不会被解除分配,因此创建这些类型对象的许多应用程序可能会看到内存使用量增加。预计将在 3.14 版本中解决此问题。
此外,代码中的数字和字符串字面量以及sys.intern()
返回的字符串也被永生化。预计此行为将保留在 3.14 的自由线程构建中。
帧对象¶
从其他线程访问帧对象是不安全的,这样做可能会导致程序崩溃。这意味着sys._current_frames()
在自由线程构建中通常不安全。诸如inspect.currentframe()
和sys._getframe()
之类的函数通常是安全的,前提是不将生成的帧对象传递给另一个线程。
迭代器¶
在多个线程之间共享同一个迭代器对象通常是不安全的,并且线程在迭代时可能会看到重复或丢失的元素,或者使解释器崩溃。
单线程性能¶
与默认的启用 GIL 的构建相比,自由线程构建在执行 Python 代码时具有额外的开销。在 3.13 中,pyperformance套件上的开销约为 40%。在 C 扩展或 I/O 中花费大部分时间的程序将看到较小的影响。最大的影响是因为在自由线程构建中禁用了专门的自适应解释器(PEP 659)。我们希望在 3.14 版本中以线程安全的方式重新启用它。预计在即将发布的 Python 版本中,这种开销将会减少。我们的目标是,与默认的启用 GIL 的构建相比,pyperformance 套件上的开销为 10% 或更少。