Python的GIL详解

GIL是Python解释器中的全局解释器锁,确保同一时刻只有一个线程执行代码,防止内存管理中的竞争条件。GIL的存在使得CPU绑定的多线程Python程序性能受限,但在I/O绑定的程序中影响较小。尽管有负面影响,但GIL因避免死锁和简化内存管理而保留,Python 3对此进行了改进。处理GIL的一种方式是使用多进程而非多线程,或选择其他Python解释器实现。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

GIL详解

GIL全称global interpreter lock,全局解释器锁,是 Python 解释器中的一个布尔值,受到互斥保护。这个锁被 CPython 中的核心字节码用来评估循环,并调节用来执行语句的当前线程。

每个线程在执行的时候都需要先获取GIL,保证同一时刻只有一个线程可以执行代码,即同一时刻只有一个线程使用CPU。执行单线程程序的开发人员看不到GIL的影响,但它可能是CPU绑定多线程代码中的性能瓶颈。

由于即使在具有多个CPU核心的多线程体系结构中,GIL一次只允许一个线程执行,因此GIL已经称为Python的“臭

名昭著”的特性。

GIL为Python解决了什么问题?

Python使用引用计数来进行内存管理。这意味着在Python中创建的对象具有引用计数变量,该变量用于跟踪指向

该对象的引用数。当此技术达到0的时候,释放对象占用的内存

示例

import  sys
a = []
b = a
sys.getrefcount(a) # 查看空列表的引用次数。

在上面的示例中,空列表对象的引用计数为3,a和b参数引用各一次,在调用sys.getrefcount()的时候也引用一

次。

回到GIL:

问题是这个引用计数变量需要防止竞争条件,如果其中两个线程同时增加或减少其值。发生这种情况,它可能导致

从未释放的内存泄漏,或者更糟糕的是,在对该对象的引用仍然存在时错误地释放内存。这可能会导致Python程

序中出现崩溃或其他“怪异”错误。

通过向跨线程共享的所有数据结构添加,可以保持此引用计数变量的安全性,从而保证不会对它们进行不一致的

修改。

但是为每个对象或对象组添加一个锁意味着将存在多个锁,这可能导致另一个问题 - 死锁(死锁只有在有多个锁时

才会发生)。另一个问题是由于重复获取和释放锁而导致的性能下降。

GIL是解释器本身的一个锁,它增加了一条规则,即执行任何Python字节码都需要获取解释器锁。这可以防止死锁

(因为只有一个锁)并且不会引入太多的性能开销。但它也让任何受CPU限制的Python程序都是单线程的。

GIL虽然被解释器用于其他语言(如Ruby),但并不是解决此问题的唯一方法。有些语言通过使用除引用计数之外

的方法(例如垃圾收集)来避免需要GIL对线程安全内存管理。

另一方面,这意味着这些语言通常需要通过添加其他性能提升特性(如 JIT编译器 )来弥补GIL单线程性能优势的

损失。

为什么选择GIL作为解决方案

那么为什么要在Python中使用GIL呢?

自从操作系统没有线程概念以来,Python就已存在。Python的设计易于使用,以便更快地开发,越来越多的开发

人员开始使用它。

有许多扩展正在为那些Python中需要其特性的C语言库而编写、服务。为了防止不一致的更改,这些C扩展需要

GIL提供的线程安全内存管理。

GIL易于实现,很容易添加到Python中。它为单线程程序提供了性能提升,因为只需要管理一个锁。

非线程安全的C库变得更容易集成。这些C扩展成为不同社区容易采用Python的原因之一。

正如您所看到的,GIL是一个实用的解决方案,可以解决CPython开发人员在Python生命中早期面临的一个难题。

对多线程的Python程序影响

当你在查看一个典型的Python程序——或任何计算机程序时,它们在性能上受CPU限制与受I / O限制是存在区别

的。(这里的意思是说,不同的程序&#x

评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值