2

来自 Java 的 Ruby 和 Python 中的整个全局解释器锁 (GIL) 有点令人吃惊。我已经阅读了一些问题,并在Python 文档中找到了以下摘录:

我们不能摆脱全局解释器锁吗?

全局解释器锁 (GIL) 通常被视为 Python 在高端多处理器服务器机器上部署的障碍,因为多线程 Python 程序有效地只使用一个 CPU,因为坚持(几乎)所有 Python 代码只能在持有 GIL 时运行。

早在 Python 1.5 时代,Greg Stein 实际上实现了一个全面的补丁集(“自由线程”补丁),它移除了 GIL 并用细粒度锁定取而代之。不幸的是,即使在 Windows(锁非常有效)上,它运行普通 Python 代码的速度大约是使用 GIL 的解释器的两倍。在 Linux 上,性能损失更严重,因为 pthread 锁效率不高。

我没有找到性能影响背后的解释。我试图找出技术原因是什么,但找不到任何好的讨论来确定它。

在 Ruby 中类似,在这里我可以找到更少的信息。原因是一样的吗?

4

2 回答 2

3

简单地说,锁定和解锁许多锁比锁定和解锁单个锁更昂贵。这应该不足为奇,做任何事情N 次而不是一次明显需要更多时间(所有其他事情都相同)。对于这种事情,规模经济并不真正适用,没有大的一次性成本来摊销所有锁定操作。

编辑:原则上,Java 也有同样的问题,但由于参与的每个人的关注点不同,历史,也许还有其他因素,Java 在细粒度锁方面做得很好。简而言之,单线程性能并不那么重要,多线程性能可能比假设的自由线程 CPython 更好。

从历史上看,我认为从来没有一个带有 GIL 的 JVM(尽管它开始时是在单个 OS 线程上运行绿色线程 - 但这是很久以前的事了),所以保留 GIL 没有历史原因,也没有基础 -线单线程的性能让人讨厌锁。取而代之的是,为了让Java擅长多线程而付出了很多努力,并且这种能力得到了广泛的应用。java.util.concurrent相比之下,即使您在没有单线程 Python 或 Ruby 程序的性能成本的情况下解决了 GIL 问题,大多数代码也不会从中受益,而且这些库......不是很糟糕,但与任何一个都不完全相提并论.

因为Java(现在)有一个显式地不提供很多保证的内存模型,所以Java程序中的许多常见操作通常不需要任何类型的锁。当然,缺点是 Java 程序员必须在需要时手动添加锁或其他同步。此外,Java 的锁已经看到了很多对锁的优化(其中一些是原始研究并首次在 JVM 中引入)——瘦锁、锁省略等——这使得具有争用的锁非常便宜。

另一个因素可能是 Java 程序几乎完全运行 Java 代码(正如我上面所描述的,如果没有明确请求,它只需要很少的同步),只需要很少调用运行时库。因此,一个自由线程的 JVM 甚至可以为 JIT、类加载器等拥有一个全局锁(或只有几个粗锁),而不会对大多数 Java 程序造成太大影响。相比之下,Python 程序将大部分时间花在 C 代码中,无论是内置模块还是第三方扩展模块。

于 2013-08-21T23:44:13.677 回答
1

大多数 Python 程序都是单线程的。那些不是通常朝着多处理方向发展的。

对于那些不适合多处理的,可以使用 C 扩展来释放 GIL,但你当然必须非常小心。

每次删除 GIL 的尝试都对所有这些单线程/多处理应用程序的性能产生了严重影响,因此 GIL 保留下来,每个人都试图利用多处理,在大多数情况下,它是最好的解决方案。

于 2013-08-22T00:05:36.633 回答