Python 迎来历史性变革:告别“全局解释器锁”,性能枷锁被打破

B站影视 韩国电影 2025-06-17 19:17 1

摘要:在编程世界里,Python 语言以其简洁的语法和庞大的生态系统,赢得了无数开发者的青睐。然而,一个长期存在的设计却让它在多核处理器时代备受诟病,那就是“全局解释器锁”(Global Interpreter Lock,简称 GIL)。许多来自其他编程语言的软件工

导语

python

在编程世界里,Python 语言以其简洁的语法和庞大的生态系统,赢得了无数开发者的青睐。然而,一个长期存在的设计却让它在多核处理器时代备受诟病,那就是“全局解释器锁”(Global Interpreter Lock,简称 GIL)。许多来自其他编程语言的软件工程师会因此得出一个结论:“Python 很慢!”。如今,这场旷日持久的争论终于迎来了历史性的转折。一项名为 PEP 703 的提案已被 Python 社区正式接受,计划在未来几年内,逐步移除 GIL。

这不仅仅是一次技术更新,它预示着 Python 即将解开长久以来束缚其多线程并行能力的枷锁。本文将带您深入了解 GIL 的前世今生,剖析它为何成为性能瓶颈,并详细解读 PEP 703 提案将如何引领 Python 迈入一个真正的多核新时代。更重要的是,我们将提供一份详尽的实操指南,教您如何在自己的电脑上安装并亲身体验没有 GIL 的 Python。

要理解这场变革的意义,我们首先需要弄明白 GIL 究竟是什么。

简单来说,全局解释器锁(GIL)本质上是一个互斥锁(mutex),它的核心作用是确保在任何一个时刻,只有一个线程能够执行 Python 的字节码。想象一下,Python 解释器是一个工作间,多个线程是多个工人,而 GIL 就是这个工作间唯一的门禁卡。无论有多少个工人(线程)排队,只有拿到门禁卡的那一个才能进入工作间干活,其他工人则必须在门外等待。

这个设计诞生于上世纪 90 年代初期,当时的主流计算机普遍使用单核 CPU。在那个年代,GIL 的存在是一个非常明智的选择。它极大地简化了 Python 语言自身的设计,为开发者提供了一种简单直接的线程安全保障,避免了复杂的内存管理问题。同时,它也简化了 Python 与 C 语言编写的扩展库(C extensions)的集成过程,这在很大程度上促进了 Python 生态的早期繁荣和稳定,为其快速赢得开发者社群的喜爱奠定了基础。可以说,在特定的历史时期,GIL 是 Python 成功的功臣之一。

然而,时间快进到 2025 年的今天,单核 CPU 早已成为历史的尘埃,多核处理器成为了个人电脑和服务器的标配。曾经的优势,如今却成了 Python 发展的最大掣肘之一。

任何一项技术决策,都带有其时代背景的烙印,也必然会带来相应的后果。GIL 这个大胆的语言设计选择,其最直接的后果就是:Python 的多线程无法真正实现并行计算

在一个拥有 8 核 CPU 的现代计算机上,理论上我们可以同时运行 8 个计算任务。但是,由于 GIL 的存在,一个 Python 进程即使创建了 8 个线程,这 8 个线程也无法同时利用这 8 个 CPU 核心。它们依然需要排队争抢唯一的 GIL,本质上还是在单个核心上进行着高速的、轮流的“伪并行”执行。这使得 Python 在处理 CPU 密集型(CPU-bound)的多线程任务时,表现得非常低效。例如,进行大规模科学计算、数据分析或者复杂的算法处理时,多线程带来的性能提升微乎其微。

为了绕过这个巨大的限制,开发者社区在过去几十年里探索出了多种变通方案。

多进程(Multiprocessing):既然一个进程内的多线程无法并行,那就创建多个独立的进程。每个进程都有自己独立的 GIL 和内存空间,操作系统可以将这些进程分配到不同的 CPU 核心上,从而实现真正的并行计算。使用外部库:利用像 NumPy 或 Cython 这样的库,将计算密集型的任务“外包”给由 C 或其他编译型语言编写的底层代码执行。这些底层代码不受 GIL 的限制,可以充分利用多核性能。

虽然这些变通方案在实践中确实有效,但它们也带来了新的问题:引入了额外的复杂性、进程间通信的开销以及更高的资源消耗。这就像是为了解决一个问题,又不得不引入好几个新的工具和流程,增加了整个项目的维护难度。

因此,在 Python 社区内部,彻底移除 GIL 的呼声从未停止。然而,这并非易事。就连 Python 的创造者 Guido van Rossum 也曾撰文坦言,移除 GIL 极其困难。他表示,如果有一个方案能在不损害单线程程序性能、不破坏向后兼容性的前提下移除 GIL,他会非常欢迎,但要同时满足这些条件是极为苛刻的挑战。

正因如此,多年来 Python 社区一直没有一个明确且可行的计划来移除 GIL,直到 PEP 703 方案的出现,才真正带来了破局的希望。

PEP 703 是由开发者 Sam Gross 提出并被社区接受的一项提案,其核心目标是让 GIL 成为一个可选项。

需要明确的是,该提案并非要立即在所有 Python 版本中废除 GIL,而是引入了一个新的编译时选项 --disable-gil。开发者可以通过这个构建配置标志,来编译一个不包含 GIL 的、实验性的 Python 版本。

Sam Gross 的创新方法成功地解决了过去移除 GIL 时遇到的几个核心障碍:

有偏向的引用计数 (Biased Reference Counting):这是解决 GIL 移除后线程安全内存管理的关键。它通过为每个线程设置本地的引用计数器,来减少多线程环境下频繁加锁带来的性能开销。不朽对象 (Immortal Objects):对于像整数、单例等频繁使用且不可变的对象,将它们标记为“不朽”,使其引用计数永远不会改变。这样一来,就无需在多线程访问这些对象时进行不必要的加锁操作,从而提升效率。线程安全的内存管理 (Thread-safe Memory Management):采用像 mimalloc 这样的现代内存分配器,来高效地处理并发环境下的内存分配和回收操作,确保稳定性和性能。

Python 指导委员会已经接受了 PEP 703,并规划了一个谨慎的、分阶段的实施路线图:

第一阶段:Python 3.13 (2024年已发布):提供一个可选的、无 GIL 的构建版本。此阶段的主要目的是为了测试和收集社区的反馈,通过 --disable-gil 编译标志来启用。第二阶段:过渡阶段 (约 2026–2027年):计划统一标准版和无 GIL 版的构建,届时开发者或许可以在运行时通过开关来切换 GIL 的启用状态,这将大大简化开发和部署流程。第三阶段:未来目标 (约 2028年以后):让无 GIL 的 Python 成为默认版本。到那时,Python 将彻底释放其在多核处理器上的并行计算潜力,成为所有开发者的默认选择。

理论说了很多,现在让我们动手实践一下,看看如何在自己的电脑上真正禁用 GIL。

以下步骤以 macOS 15.5 系统为例,其他操作系统上的流程应该类似,但具体操作可能略有不同。

第一步:下载 Python 3.13 安装包

首先,我们需要访问 Python 的官方网站,下载最新的 Python 3.13 安装程序。请确保根据你的操作系统(Windows、macOS 等)选择正确的版本。

第二步:在安装过程中启用实验性功能

下载完成后,打开安装程序。在“安装类型”(Installation Type)这一步骤,你会看到一个关键选项:“Free-threaded Python [experimental]”(自由线程 Python [实验性])。这个选项默认是未勾选的,你必须手动勾选它,然后再继续完成安装。

第三步:安装 SSL 证书

安装完成后,在访达(Finder)中打开 /Applications/Python 3.13/ 目录,找到并执行一个名为“Install Certificates.command”的脚本文件。这一步是为了给新安装的 Python 配置 SSL 根证书,以便它能正常进行网络请求等操作。

第四步:验证安装结果

完成以上步骤后,你的系统中实际上安装了两个 Python 3.13 应用:一个标准的 Python 3.13 和一个实验性的 Python 3.13t。其中,末尾带 't' 的就是我们期待的无 GIL 版本。

要使用它,只需在终端(Terminal)中输入 python3.13t 即可。

为了验证 GIL 是否真的被禁用了,我们可以打开两个终端窗口,分别运行标准版和无 GIL 版的 Python,并输入以下代码: import sysconfig sysconfig.get_config_var("Py_GIL_DISABLED")

你会看到,在 python3.13 中,该命令返回 False 或 0;而在 python3.13t 中,它会返回 True 或 1。这证明我们已经成功进入了没有 GIL 的世界!。

为了直观感受性能差异,我们来运行一个简单的测试脚本。这个脚本会创建 4 个线程,每个线程都执行一个 CPU 密集型的计算任务。

import threadingimport time# 一个消耗 CPU 的计算任务def cpu_bound_task(n, thread_id): count = 0 for i in range(n): count += i*iN = 100000000 # 设定一个较大的计算量def run_with_threads: threads = start = time.time # 创建并启动 4 个线程 for i in range(4): t = threading.Thread(target=cpu_bound_task, args=(N, i)) threads.append(t) t.start # 等待所有线程执行完毕 for t in threads: t.join end = time.time print(f'总耗时: {end - start:.2f} 秒')if __name__ == '__main__': run_with_threads

测试结果:

使用标准 Python 3.13 运行: 在终端输入 python3.13 your_script_name.py。 得到的运行时间是 13.51 秒使用无 GIL 的 Python 3.13t 运行: 在终端输入 python3.13t your_script_name.py。 得到的运行时间是 3.74 秒!。

结果一目了然。在多线程执行 CPU 密集型任务时,无 GIL 的 Python 耗时仅为标准版的约 1/3.6。数字雄辩地证明了:没有了 GIL,Python 终于实现了真正的多线程并行计算。

“要不要 GIL”,这个问题在 Python 社区争论了多年,在可预见的未来,它将不再是一个问题。

这场变革得到了社区的广泛支持,尤其是来自数据科学和人工智能领域的工程师们,他们热切期盼着这次性能飞跃。包括 Meta 在内的一些科技巨头,也已经投入了大量资源来支持这一过渡。

那么,对于广大的 Python 开发者来说,这意味着什么?我们现在应该怎么做?

最重要的一条建议是:现阶段,请不要在生产环境中使用无 GIL 的 Python

当前发布的 Python 3.13 无 GIL 版本,其定位仅仅是一个“实验性”构建。关于它的兼容性、长期稳定性以及整个生态系统(尤其是大量的第三方库)的适配情况,都还存在许多不确定性,需要时间来逐步完善和检验。

但是,我们绝对应该对此保持密切关注。移除 GIL 是 Python 发展史上的一个里程碑事件,它正在真实地发生。开发者可以开始在本地环境中进行实验,了解其特性,并思考如何在未来的项目中利用这一优势。

人生苦短,我用 Python。现在,你又多了一个选择 Python 的理由。这场激动人心的变革已经拉开序幕,让我们拭目以待。

来源:高效码农

相关推荐