0
点赞
收藏
分享

微信扫一扫

Python 中的全局解释器锁 (GIL):全面的历史

全局解释器锁,通常称为 GIL,自 Python 诞生以来一直是 Python 讨论最多的功能之一。GIL 是一种互斥锁,可保护对 Python 对象的访问,防止多个本机线程同时执行 Python 字节码。虽然它简化了 CPython(使用最广泛的 Python 实现)中的内存管理,但它也一直是争议的来源,尤其是在多线程应用程序中。

全局解释器锁 (GIL) 的诞生

Python 的早期(1980 年代末至 1990 年代初)

Python 由 Guido van Rossum 于 1980 年代后期创建,第一个正式版本 Python 1.0 于 1991 年发布。从一开始,Python 就致力于成为一种易于使用、注重可读性的高级语言。但是,在实现该语言时,尤其是在 CPython 中,Python 的参考实现、内存管理和对象访问是关键问题。

在早期,计算机主要是单核的,多线程应用程序并不常见。GIL 是作为一种简单的解决方案引入的,用于保护 Python 的内部数据结构,尤其是其内存管理系统中使用的引用计数。通过确保一次只有一个线程可以执行 Python 字节码,GIL 简化了解释器的实现,避免了复杂且容易出错的代码,以实现线程安全的内存管理。

为什么 GIL 最初有意义

使用 GIL 的决定是务实的:

  • 简单性:GIL 允许实现 Python 解释器,而无需对 Python 对象上的每个操作进行精细锁定。
  • 性能:在单核计算机上,GIL 不是性能瓶颈,因为无论如何,一次只能执行一个线程。GIL 带来的开销可以忽略不计。

当时,权衡似乎是合理的,GIL 允许 Python 快速发展和进化,而不会因线程管理的复杂性而陷入困境。

GIL 的成长之痛

多核处理器的出现(2000 年代)

随着多核处理器在 2000 年代初期成为常态,GIL 的局限性变得更加明显。开发人员开始编写更多的多线程应用程序,GIL 很快从一个有用的功能变成了一个重要的瓶颈。由于 GIL 一次只允许一个线程执行 Python 字节码,因此 Python 程序无法充分利用多核系统的计算能力。

社区抵制和删除 GIL 的尝试

多年来,Python 社区曾多次尝试删除或替换 GIL:

  • Greg Stein 的 Free-threading Patch (1999):最早删除 GIL 的尝试之一来自 Greg Stein,他提出了一个引入细粒度锁来替换 GIL 的补丁。但是,性能开销太高,并且该补丁从未进入主线 Python 代码库。
  • Python 3000 讨论(2000 年代):在 Python 3.0(也称为 Python 3000)的开发过程中,围绕删除 GIL 进行了大量讨论。但是,保持向后兼容性的挑战和替代解决方案的复杂性意味着 GIL 被保留。

全局解释器锁 (GIL) 变得可选

持续的挫折和替代的 Python 实现

随着 Python 的不断普及,人们对 GIL 的挫败感也越来越大。一些开发人员转向没有 GIL 的替代 Python 实现:

  • Jython 和 IronPython:这些实现分别基于 Java 和 .NET 生态系统,没有 GIL,允许真正的多线程。但是,它们缺乏 CPython 的广泛库支持。
  • PyPy:PyPy 是另一种替代实现,它侧重于通过即时 (JIT) 编译器实现性能。虽然 PyPy 也使用 GIL,但它在其他领域的速度改进使其成为一个受欢迎的选择。

Python 3.2:GIL 经过重新设计

在 Python 3.2 中,全局解释器锁没有被删除,但得到了显著改进。Python 核心开发人员 Antoine Pitrou 重新设计了 GIL,以减少争用并提高多线程性能。这是一个受欢迎的变化,但它并没有消除 GIL 在多核处理器上的固有限制。

Python 3.12:每个解释器 GIL 优化

全局解释器锁 (GIL) 发展的一个重要里程碑出现在 Python 3.12 中。此版本引入了“Per-Interpreter GIL”优化,这是对传统全局 GIL 模型的重大转变。通过此更改,Python 进程中的每个子解释器都会收到自己的 GIL,从而允许子解释器并发运行而不会相互干扰。

这一改进大大减少了使用多个子解释器的多线程应用程序中的 GIL 争用,从而可以在单个进程中实现更好的并行性。虽然这并没有完全消除 GIL,但这是减少其影响的关键一步,尤其是在涉及复杂的多线程工作负载的情况下。

逐步淘汰 GIL:Python 3.13 之路

真正的突破出现在 2020 年代,随着社区压力的增加以及硬件和软件工程的进步。Python 指导委员会和核心开发人员开始积极探索逐步淘汰 GIL 或使其成为可选的方法。

  • 子解释器和 PEP 554:Python 增强提案 554 引入了子解释器的概念,允许同一进程中的不同 Python 解释器同时运行,而无需共享 GIL。这为更精细的并发铺平了道路。
  • PEP 684:每个解释器 GIL:另一个重要的步骤是引入了 PEP 684,它提出了每个解释者 GIL,允许每个子解释器都有自己的 GIL,从而在单个过程中实现真正的并行性。

Python 3.13:GIL 变为可选

最后,随着 Python 3.13 的发布,全局解释器锁 (GIL) 已成为可选选项。开发人员现在可以在构建 Python 时选择禁用 GIL,从而在 CPython 中实现真正的多线程性能。这是一个巨大的变化,反映了几十年的演变,并解决了对 Python 最重要的批评之一。

  • 选择退出 GIL:在构建 Python 3.13 时,开发人员可以使用配置选项来禁用 GIL。这涉及使用细粒度锁和其他机制来管理并发,但它在单线程性能方面会带来一些权衡。


举报

相关推荐

0 条评论