global interpreter lock (GIL)通常被视为 Python 在高端多核服务器上开发时的阻力,因为(几乎)所有 Python 代码只有在获取到 GIL 时才能运行,所以多线程的 Python 程序只能有效地使用一个 CPU。

在 Python 1.5 时代,Greg Stein 开发了一个完整的补丁包("free threadings” 补丁),移除了 GIL,并用粒度更合适的锁来代替。Adam Olsen 最近也在他的 python-safethread 项目里做了类似的实验。不幸的是,由于为了移除 GIL 而使用了大量细粒度的锁,这两个实验在单线程测试中的性能都有明显的下降(至少慢 30%)。

但这并意味着你不能在多核机器上很好地使用 Python!你只需将任务划分为多*进程*,而不是多*线程*。新的 concurrent.futures 模块中的 ProcessPoolExecutor 类提供了一个简单的方法;如果你想对任务分发做更多控制,可以使用 multiprocessing 模块提供的底层 API。

恰当地使用 C 拓展也很有用;使用 C 拓展处理耗时较久的任务时,拓展可以在线程执行 C 代码时释放 GIL,让其他线程执行。zlib 和 hashlib 等标准库模块已经这样做了。

也有建议说 GIL 应该是解释器状态锁,而不是完全的全局锁;解释器不应该共享对象。不幸的是,这也不可能发生。由于目前许多对象的实现都有全局的状态,因此这是一个艰巨的工作。举例来说,小整型数和短字符串会缓存起来,这些缓存将不得不移动到解释器状态中。其他对象类型都有自己的自由变量列表,这些自由变量列表也必须移动到解释器状态中。等等。

我甚至怀疑这些工作是否可能在优先的时间内完成,因为同样的问题在第三方拓展中也会存在。第三方拓展编写的速度可比你将它们转换为把全局状态存入解释器状态中的速度快得多。

最后,假设多个解释器不共享任何状态,那么这样做比每个进程一个解释器好在哪里呢?