Python 对自由线程的支持¶
从 3.13 版本开始,CPython 支持一个名为自由线程的 Python 构建,其中全局解释器锁 (GIL) 已禁用。自由线程执行允许通过在可用 CPU 核心上并行运行线程来充分利用可用的处理能力。虽然并非所有软件都会自动受益,但针对多线程设计的程序将在多核硬件上运行得更快。
自由线程模式正在运行并持续改进,但与常规构建相比,单线程工作负载会增加一些开销。此外,第三方包,特别是那些带有扩展模块的包,可能尚未准备好在自由线程构建中使用,并将重新启用GIL。
本文档描述了自由线程对 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
包含“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 版本中减少。我们的目标是 pyperformance 套件上的开销与默认的 GIL 启用构建相比为 10% 或更少。
行为变化¶
本节描述了自由线程构建中 CPython 的行为变化。
上下文变量¶
在自由线程构建中,标志thread_inherit_context
默认设置为 true,这使得使用threading.Thread
创建的线程以调用start()
的调用者的Context()
副本启动。在默认的 GIL 启用构建中,该标志默认为 false,因此线程以空的Context()
启动。
警告过滤器¶
在自由线程构建中,标志context_aware_warnings
默认设置为 true。在默认的 GIL 启用构建中,该标志默认为 false。如果标志为 true,则warnings.catch_warnings
上下文管理器使用上下文变量进行警告过滤。如果标志为 false,则catch_warnings
修改全局过滤器列表,这并非线程安全。有关更多详细信息,请参阅warnings
模块。