Python 对自由线程的实验性支持
*****************************

从 3.13 版开始，CPython 实验性地支持 *free threading* (自由线程) 的
Python 构建，其禁用 *global interpreter lock* (GIL)。自由线程化的执行
允许在可用的 CPU 上并行运行线程，充分利用可用的处理能力。尽管并非所有
软件都能自动地从中受益，但是考虑到线程设计的程序在多核硬件上运行速度会
更快。

**自由线程模式是实验性的**，改进工作正在进行中：预计会出现一些错误，单
线程性能也会受到很大影响。

本文档描述了自由线程对 Python 代码的影响。 请参阅 自由线程的 C API 扩
展支持 了解如何编写支持自由线程构建的 C 扩展。

参见: **PEP 703** —— 查阅《在 CPython 中使全局解释器锁成为可选项》以了解对
    自由线程 Python 的整体描述。


安装
====

从 Python 3.13 开始，官方 macOS 和 Windows 安装器提供了对可选安装自由
线程 Python 二进制文件的支持。 安装器可在
https://www.python.org/downloads/ 获取。

有关其他平台的描述，请参阅 安装自由线程 Python，这是一份由社区维护的，
用于安装自由线程 Python 的安装指南。

当从源码构建 CPython 时，应使用 "--disable-gil" 配置选项以构建自由线程
Python 解释器


识别自由线程 Python
===================

要检查当前解释器是否支持自由线程，查看 "python -VV" 和 "sys.version"
是否包含 "experimental free-threading build"。新的
"sys._is_gil_enabled()" 函数可用于检查在运行进程中全局解释器锁是否确实
被关闭。

"sysconfig.get_config_var("Py_GIL_DISABLED")" 配置变量可用于确定构建是
否支持自由线程 。 如果该变量设置为``1`` ，则构建支持自由线程。这是与构
建配置相关的决策的推荐机制。


自由线程版 Python 中的全局解释器锁
==================================

CPython 的自由线程构建版支持在运行时使用环境变量 "PYTHON_GIL" 或命令行
选项 "-X gil" 选择性地启用 GIL。

GIL 也可能在导入未显式标记为支持自由线程模式的 C-API 扩展模块时被自动
启用。 在这种情况下将会打印一条警告。

在单独软件包的文档以外，还有下列网站在追踪热门软件包对自由线程模式的支
持状态：

* https://py-free-threading.github.io/tracking/

* https://hugovk.github.io/free-threaded-wheels/


线程安全
========

自由线程构建的 CPython 旨在 Python 层级提供与默认全局解释器锁启用构建
相似的线程安全行为。内置类型（如 "dict" 、 "list" 和 "set" 等）使用内
部上锁来防止并发修改，其行为方式与全局解释器锁相似。 但是，Python 历来
不对这些内置类型的并发修改提供特定的行为提供保证，因此这应被视为对当前
实现的描述，而不是对当前或未来行为的保证。

备注:

  建议尽可能使用 "threading.Lock" 或其他同步的原语，而不是依赖内置类型
  的内部上锁 。


已知的限制
==========

本节介绍自由线程 CPython 构建的已知限制。


永生化
------

3.13 版本的自由线程构建使某些对象 *immortal*。 永生对象不会被重新分配
，其引用计数永远不会被修改。 这样做是为了避免引用计数发生争夺，以免妨
碍高效的多线程扩展。

当主线程运行后首次启动新的线程时，对象将被永生化。 以下对象将被永生化
：

* 在模块中声明的 函数 对象

* 方法 描述器

* 代码对象

* *module* 对象及其字典

* 类 (类型对象)

由于永生对象永远不会被重新分配，因此应用如果创建了许多此类对象，可能会
增加内存使用。预计 3.14 版将解决这个问题。

此外，代码中的数字和字符串字面值以及 "sys.intern()" 返回的字符串也将永
久化。 预计在 3.14 自由线程构建中将保留这一行为 。


帧对象
------

从其他线程访问 帧 对象是不安全的，这样做可能会导致程序崩溃。 这意味着
，在自由线程构建中使用 "sys._current_frames()" 一般是不安全的。 函数（
如 "inspect.currentframe()" 和 "sys._getframe()" 等）只要不将生成的帧
对象传递给另一个线程，一般都是安全的。


迭代器
------

在多个线程之间共享同一个迭代器对象通常是不安全的，线程在迭代时可能会出
现元素重复或缺失的情况，或使解释器崩溃。


单线程性能
----------

与启用默认全局解释器锁的构建相比，自由线程构建在执行 Python 代码时有额
外的开销。 在 3.13 中，pyperformance 套件的开销约为 40%。大部分时间花
在 C 扩展或 I/O 上的程序受到的影响较小。影响最大的原因是在自由线程构建
中禁用了特化自适应解释器 (**PEP 659**) 。 我们希望在 3.14 中以线程安全
的方式重新启用它。在即将发布的 Python 版本中，这一开销有望减少。 我们
的目标是，与启用默认全局解释器锁的构建相比，pyperformance 套件的开销不
超过 10%。
