假设你有一个计算器(相当于 Python 解释器),而 GIL 就是这个计算器的 **"使用权"**。
多线程的情况(没绕过 GIL):
你和同事(两个线程)共用这一个计算器
规定是:同一时间只能有一个人用计算器(GIL 的限制)
你用的时候,同事只能等着;你用完了,同事才能接着用
哪怕你们算的是不同的题,也不能同时碰计算器
这就是多线程的问题:不管有多少个线程,都得抢同一个 GIL,同一时间只有一个能执行。
多进程的情况(绕过 GIL):
你和同事各拿一个计算器(每个进程有自己的 Python 解释器)
你的计算器有你的 GIL,同事的计算器有他的 GIL
你们可以同时用自己的计算器算题,互不干扰
因为是两个独立的计算器,各自的 GIL 不会互相影响
这就是多进程能绕过 GIL 的原因:每个进程都有自己独立的解释器和 GIL,它们之间没有竞争关系,可以真正并行工作。
多线程:大家抢同一把 GIL 钥匙,轮流用一个解释器
多进程:每个人都有自己的 GIL 钥匙和解释器,各自用各自的
gil_comparison.py
import threading
import multiprocessing
import time
# 一个CPU密集型任务:计算大量数字的和
def heavy_task():
total = 0
# 执行大量计算(CPU密集型)
for i in range(10**8): # 1亿次循环
total += i
return total
# 测试1:使用多线程(未绕过GIL)
def test_threads():
start = time.time()
# 创建两个线程
t1 = threading.Thread(target=heavy_task)
t2 = threading.Thread(target=heavy_task)
# 启动线程
t1.start()
t2.start()
# 等待完成
t1.join()
t2.join()
print(f"多线程(未绕过GIL)耗时: {time.time() - start:.2f}秒")
# 测试2:使用多进程(绕过GIL)
def test_processes():
start = time.time()
# 创建两个进程
p1 = multiprocessing.Process(target=heavy_task)
p2 = multiprocessing.Process(target=heavy_task)
# 启动进程
p1.start()
p2.start()
# 等待完成
p1.join()
p2.join()
print(f"多进程(绕过GIL)耗时: {time.time() - start:.2f}秒")
if __name__ == "__main__":
test_threads() # 未绕过GIL
test_processes() # 绕过GIL
GIL(全局解释器锁)并不是 Python 独有的,但它在 Python 中(尤其是最常用的 CPython 解释器)非常有名,因为它对 Python 多线程性能影响很大。