亚马逊AWS官方博客

是时候说线程自由了吗?

引言

自 1991 年诞生以来,Python 凭借其多功能性、易学性以及丰富的库生态系统,始终占据编程语言领域的领先地位。然而,其性能问题,尤其是全局解释器锁(GIL)对多线程的限制,一直是开发者关注的焦点。2024 年,Python 3.13 引入了实验性的线程自由技术,这一突破性进展标志着 Python 向真正的多线程并行迈出了关键一步。本文将深入探讨 GIL 的历史、线程自由的实现及其对 Python 未来的影响。

性能的争议

严格的说来,我们所谈论的 Python 其实只是一个用C语言编写的 Python 的参考实现,正式的名称为 CPython。 除此之外,业内还有 PyPy、Pyston、Codon 以及 MicroPython 等小众且各具特色的 Python 实现。

正如 Kent Beck 说过的那句话,“Make it work, Make it right, Make it fast”. Python 也发展到今天,性能问题已成为其最大的短板。那么,究竟性能有多糟糕,还是用一段斐波那契数列计算的代码来做一个对比:

程序语言:Python3.12 程序语言:Rust
运行环境:Amazon EC2 c7g.8xlarge 运行环境:Amazon EC2 c7g.8xlarge
import sys

def fibo(n):
    if n <= 1:
        return n
    else:
        return fibo(n-1) + fibo(n-2)

if __name__ == '__main__':
    for n in sys.argv[1:]:
        print(n, fibo(int(n)))
use std::env;

pub fn fibo(n: u32) -> u32 {
    match n {
        0 => 0,
        1 => 1,
        _ => fibo(n - 1) + fibo(n - 2),
    }
}

pub fn main() {
    let args: Vec<String> = env::args().skip(1).collect();
    for arg in args.iter() {
        let n: u32 = arg.parse().unwrap();
        println!("fibo({}) = {}", n, fibo(n));
    }
}
python3.12 fibonacci.py 10 20 30 40 ./fibonacci 10 20 30 40
运行时间:14.178 秒 运行时间:1.014 秒

现在我们知道了,在这个例子中 Rust 可以比 Python 3.12 快了 14 倍!

作为对于质疑的回应,过去的几十年每当 Python 发布新版本,我们都会听到关于性能优化的消息,这给人一种感觉,这门语言的速度正在一点一点地提升。那么,我们现在是否能真正的解决这个顽疾呢?这就要提到 一个争议不断的话题:全局解释器锁(GIL)。许多观点认为正是 GIL 拉低了 Python 的性能。

全局解释器锁(GIL)的起源与影响

全局解释器锁(GIL)是 CPython 并发模型的核心机制,用于保护解释器内部数据结构免受多线程并发访问的影响,避免因多线程并发访问而导致数据不一致。简而言之,一个 Python 程序可以创建多个线程,但同一时间只有一个线程可以运行实际的 Python 代码。

虽然这种方法简化了实现以及与 C 扩展的集成,但在多核 CPU 时代,GIL 显著限制了 Python 的多线程性能但它也成为了多线程性能的瓶颈,尤其是在 CPU 密集型任务中。但如果取消 GIL,Python 的多线程程序就需要一种不同的、可能更加复杂的机制来保护这些数据结构,并且还不能导致单线程应用性能恶化等等,而这已被证明是设计上的难题。

GIL 的优势

  • 简化内存管理,确保垃圾收集的安全性。
  • 优化单线程性能,避免复杂的锁机制。
  • 保障 C 扩展的线程安全性。

GIL 的限制

  • 无法实现真正的多核并行处理。
  • CPU 密集型任务性能低下。
  • 需要依赖多进程或 C 扩展实现并行。

解决 GIL 历程

多年来,围绕 GIL 的争论始终没有停止,Python 社区为移除 GIL 付出了诸多努力:

(1)2016 年:Larry Hastings 的 Gilectomy 项目

该项目通过引入细粒度锁和原子操作尝试移除 GIL。尽管在多核环境下性能有所提升,但单线程性能下降的代价使其未被广泛采用。

(2)2020年:Sam Gross 的 nogil 方案

Sam Gross 提出了一系列改进,包括:

  • 使用 mimalloc 替换 pymalloc,提升内存分配效率。
  • 引入偏向引用计数,减少线程争用。
  • 将常用对象(如 None、True)设置为“不可变”,优化引用计数。
  • 调整垃圾收集器为线程安全的单线程模式。
  • 这些努力促成了 CPython 的“nogil”分支,验证了无 GIL 解释器的可行性。

尽管 nogil 方案并非完美,还存在 ABI 问题和互斥锁开销。这个尝试是一次突破,证明了取消 GIL 的可行性。

(3)2023年,PEP 703:使 GIL 成为可选项

2023 年,Sam Gross 起草的 PEP 703 提议 – “使 GIL 成为可选项”,并获社区通过。PEP 703 中提出的关键变更包括:

  • 允许使用或不使用 GIL 来构建 CPython 。
  • 对引用计数、内存管理和线程安全机制的调整。
  • 确保单线程性能保持竞争力。
  • 该提案已被接受,这标志着 Python 在实现完善的多线程性能方面迈出了重要的里程碑。

(4)2024 年:Python 3.13 中的实验性线程自由支持

Python 3.13 于 2024 年 10 月正式发布,首次引入对线程自由的支持。核心技术包括:

  • 细粒度锁定:为每个对象提供独立的锁机制。
  • 并发垃圾收集:允许多线程运行时安全管理内存。
  • 原子引用计数:防止线程间争用。

要强调一点,3. 13 中的线程自由被设计为可选项,而不是完全从 CPython 中删除 GIL,这是一项实验性功能,可让开发人员利用并行性,同时仍保持向后兼容性。

Python 的线程自由技术

“线程自由”可以视作是一种语言范式的转变,而不仅仅是技术上的调整。而所谓的范式转变则意味着 Python 应用将会迎来真正的多线程的时代。而我们以往习惯的 Multiprocessing、Asynio 等复杂且笨重的模式有可能迎来一个巨变。

如何安装 Python 3.13

目前在 Amazon Linux 以及 Ubuntu 等主流的 Linux 分发版本中都尚未提供 Python 3.13 的二进制安装包。打算体验这个“线程自由”的 Python 推荐使用以下两种方法:

方法 1 :使用 UV

可以使用’uv’安装免费的 Python 线程版本

$ uv python install 3.13t

方法 2 :从源代码构建

可以在 Python 构建过程中禁用 GIL。为此,需要使用 启用这个选项“–disable-gil”,从而编译出线程自由的 Python 解释器。

在 Amazon Linux 2023 环境下,需要安装以下依赖包:

$sudo dnf install -y openssl-devel bzip2-devel libffi-devel \
        readline-devel sqlite-devel xz-devel zlib-devel tk-devel \
        ncurses-devel expat-devel gdbm-devel mpdecimal-devel

编译的选项需要根据你的需要。以下是我所使用的编译设置,供参考:

./configure \
    --prefix="${prefix}"   \
    --enable-shared        \
    --with-system-expat    \
    --with-system-libmpdec \
    --with-computed-gotos  \
    --with-ssl-default-suites=openssl \
    --with-dbmliborder=bdb:gdbm \
    --enable-optimizations \
    --with-lto \
    --enable-loadable-sqlite-extensions \
    --enable-ipv6          \
    --without-static-libpython \
    --without-ensurepip        \
    --without-doc-strings      \
    --disable-gil              \
    --enable-experimental-jit="${enable_jit}"

现在我们就得到了一个线程自由的 Python 环境了:

Python 3.13.5 experimental free-threading build (main, Jun 19 2025, 14:23:18) [Clang 20.1.0 (https://github.com/arm/arm-toolchain.git 7c24e4c5c369cc0fd2d3bf62 on linux

测试 Python 3.13 中的线程自由

让我们看一些实际使用线程自由技术进行并行处理的代码示例。

运行环境如下:

  • Host: Amazon EC2 c7g.8xlarge
  • OS: Amazon Linux 2023.7.20250609 aarch64
  • Kernel: 6.12.30-34.92.amzn2023.aarch64

多线程 CPU 密集任务对比

Python 线程使用以下示例代码执行:concurrent.futures.ThreadPoolExecutor

该计算过程使用 16 线程重复 1 亿次,分别对比线程自由 vs 传统 GIL 线程

Python 3.13 线程自由 Python 3.12
5.94 秒 75.89 秒

毫无意外,线程自由版本运行更快,运行时间快了大约 13 倍。3.12 版本速度较慢,因为 GIL 的缘故,它一次只运行一个线程,但线程自由版本可以同时运行 16 个线程,因此表现更好。

多进程 CPU 密集型任务对比

现在,让我们尝试使用多进程而不是多线程的方式执行同一个任务。只需将上面的代码更改 ThreadPoolExecutor 为 ProcessPoolExecutor,就可以将多线程进程更改为多进程。

Python 3.13 线程自由 Python 3.12
6.78 秒 5.63 秒

如上所述,线程自由的目的是消除 GIL,而多进程则不受 GIL 的影响,因此我们发现在使用多进程模式时,线程自由并没有明显的优势。不仅如此,相比 GIL 下的多进程,线程自由还略有不足。不过,这个测试还是可以看出来,线程是进程内的轻量级执行单元,进程内的线程共享同一内存空间,这使得并发执行效率更高。

单线程性能对比

看过以上两组对此,我们或许更关注单线程的对比。如果在“线程自由”的模式下,但线程的性能能够媲美传统的 GIL 单线程的表现,这不正是我们翘首以盼的结果吗。这是一个简单的冒泡排序的程序,我们对其进行 10000 个数据的排序。

Python 3.13 线程自由 Python 3.12
7.19 秒 4.43 秒

看到这个结果,你一定会发问:“线程自由”为什么速度会变慢?

即使 Python 3.13 已经发布了第五个小版本,但其线程自由版本仍然存在一些已知的问题。

首先就是单线程性能下降的问题,平均而言启用线程自由会导致单线程运行时性能下降约 40%。其次,新的技术增加了内存使用量,主要是细粒度锁定和不可变对象(Immortal Objects)增加了内存的使用量。看到这里,你是否感觉“线程自由”为时尚早?

且慢,变化就在眼前。

未来的改进方向和新的 Python 3.14

为了解决这些存在的问题,针对 Python 的未来版本的改进正在进行中:

  1. 提升单线程性能:当前性能下降主要是由于 PEP 659:专用自适应解释器被禁用。Python 3.14 将以线程安全的方式重新启用它。
  2. 已修复的已知限制:已知的限制(例如由于不可变对象而导致的内存使用量增加)将在即将发布的版本中得到解决。

如果你关心这些改进的进展,不妨参考以下的链接:

让我们试用3.14.0 beta 3,这是截至目前最新的测试版本,于2025年 6 月 17 日发布。请注意,这是一个  Pre-release Testing Versions3.14版本,稳定性和性能无法保证,因此请仅将结果用作参考。

任务 Python 3.12 Python 3.13 Python3.14
simple_thread.py 75.71 秒 5.92 秒 4.38
simple_process.py 5.66 秒 6.77 秒 4.46
fibonacci.py 10 20 30 40 14.21 秒 26.22 秒 14.52
bubble_sort.py 10000 4.47 秒 7.53 秒 4.42

这个结果是否让我们感到一点振奋?更重要的一点,按照目前的路线图与计划,Python 3.14 将于 2025 年 10 月正式发布!

总结

Python 3.13 中新增了线程自由的特性。此功能将实现真正的并行处理,充分利用多核 CPU 的功能。以 Amazon EC2 为例,其 c8gd.48xlarge、m8gd.48xlarge 等实例类型已经提供 192 物理核心,如何充分利用这些现代化处理器资源已经是我们必须要面对的挑战。

正如在本文中所见,我们已经验证,在 CPU 密集型处理中启用线自由程可以加速传统的多线程处理。这扩展了 Python 中并行处理的选项,并且在某些用例中,无需使用多个进程即可通过多线程获得更高的性能。

然而,目前由于它是一项实验性功能,仍然存在一些问题,您应该仔细考虑是否在生产环境中使用它。检查您使用的库是否支持线程自由也很重要 (https://py-free-threading.github.io/tracking/)。

从 PEP 的声明来看,他们的目标是逐步过渡。而从长远来看,预计过渡将从构建时选项转向运行时控制,最终 GIL 将默认禁用。未来 Python 版本中将进一步改进线程自由技术,最终无 GIL 将成为默认设置。如果说 Python 3.13 还不能完全打动你,那么 Python 3.14 的发布无疑将会是“线程自由”的时刻!那就让让我们继续追赶技术发展的脚步吧。

撰写本文时参考了以下文献:

本篇作者

费良宏

亚马逊云科技首席开发者布道师。在过去的 20 多年一直从事软件架构、程序开发以及技术推广等领域的工作。他经常在各类技术会议上发表演讲进行分享,他还是多个技术社区的热心参与者。他擅长 Web 领域应用、移动应用以及机器学习等的开发,也从事过多个大型软件项目的设计、开发与项目管理。目前他专注与云计算以及互联网等技术领域,致力于帮助中国的开发者构建基于云计算的新一代的互联网应用。