全称:Global Interpreter Lock(全局解释器锁)。
概念:GIL 是 CPython 解释器中的一把互斥锁。
作用:无论 CPU 有多少个核心,在某一时刻,只允许同一个进程中的一个线程去执行 Python 代码,保护 Python 对象内部状态不被并发修改,简化内存管理(尤其是引用计数)。
范围:每个 Python 进程拥有一个独立的GIL(多进程不受影响)。
实现:CPython 核心的一个互斥锁,线程在运行 Python 代码前必须获得 GIL,执行完毕后释放(或主动让出)。
1️⃣ 简化内存管理(核心原因)
Python 使用引用计数来管理内存。每个对象都有一个计数器,记录被引用的次数。如果没有GIL,多个线程可能同时修改同一个对象的引用计数,导致计数错误、内存泄露或重复释放。
2️⃣ 避免复杂的细粒度锁
如果不使用 GIL,解释器需要为每个对象(整数、列表、字典等)加锁,这会造成:
3️⃣ 历史原因
Python 早期设计(1990年代)时多核 CPU 并不普及,选择 GIL 是一种务实且高效的工程决策。时至今日,许多 C 扩展库(如 NumPy)依赖 GIL 的简洁性,完全移除 GIL 将破坏大量现有代码。
4️⃣ 如果没有 GIL 锁,那么 Python 底层就可能会出现引用计数错误,导致内存“爆炸”。

基本流程
⒈线程启动时,会尝试获取 GIL。
⒉获得 GIL 的线程开始执行 Python 字节码。
⒊以下情况会释放 GIL:
I/O操作(如time.sleep()、socket.recv()、file.read())时,会主动释放。sys.setswitchinterval()调整时间间隔),会强制释放。⒋释放GIL 后,操作系统会调度另一个等待的线程获得 GIL。
关键点
1️⃣ 针对 CPU 密集型任务:
多进程替代多线程:
multiprocessing模块创建独立进程,每个进程有独立的 GIL 和内存空间,可真正并行利用多核。
调用C/C++扩展:
NumPy、Numba等库中,底层计算会主动释放 GIL,使多线程能并行执行(如矩阵运算)。2️⃣ 针对 I/O 密集型任务:
线程池优化:
concurrent.futures.ThreadPoolExecutor管理线程,避免手动创建过多线程导致切换开销。异步编程(asyncio):

结论:GIL 为了确保 CPython 解释器级别的数据安全,作为日常编码来说,我们对 GIL 是无感的,但对于Lock/RLock是实际编码中使用较多的,Lock/RLock是为了确保业务逻辑的完整。下面介绍两个Lock/RLock的示例。
示例一:让打印是完整的。
import time
from threading import Thread, RLock, current_thread
def show_info1(lock):
for _ in range(10):
with lock:
print(f'\t {current_thread().name} AA', end='')
print('AA', end='')
print('AA')
time.sleep(0.01)
def show_info2(lock):
for _ in range(10):
with lock:
print(f'\t {current_thread().name} OO', end='')
print('OO', end='')
print('OO')
if __name__ == '__main__':
lock = RLock()
t1 = Thread(target=show_info1, args=(lock,), name='show_info1')
t2 = Thread(target=show_info2, args=(lock,), name='show_info2')
t1.start()
t2.start()
示例二:不要让两个窗口卖出同一张票。
import time
from threading import Thread, RLock, current_thread
current = 1
def sale(lock):
global current
while True:
with lock:
if current <= 20:
print(f'{current_thread().name}出售了第{current}张票!')
current += 1
else:
print('票已售空')
break
time.sleep(0.3)
if __name__ == '__main__':
lock = RLock()
t1 = Thread(target=sale, name='窗口1', args=(lock,))
t2 = Thread(target=sale, name='窗口2', args=(lock,))
t3 = Thread(target=sale, name='窗口3', args=(lock,))
t1.start()
t2.start()
t3.start()
上面示例,如果不使用锁,运行结果则会出现两个窗口售出了同一张票。
🔥BuildAdmin是一个永久免费开源,无需授权即可商业使用,且使用了流行技术栈快速创建商业级后台管理系统。