写代码越久,越发现Python的GIL像个套在脖子上的紧箍咒,特别是跑CPU密集型任务的时候。说实话,一开始我也被GIL坑惨了,代码放多核机器上跑,愣是只用一个核。后来发现用多进程能完美解决这个问题,干脆今天就来聊聊这个话题。
GIL是个啥
你就想啊,Python解释器本质上就是个大管家,要时刻盯着程序里的那些变量对象。为了防止多个线程同时修改一个对象,搞出个GIL(Global Interpreter Lock)。说白了就是个大锁,同一时间只让一个线程执行Python字节码。
import threading
import time
counter = 0
def increment():
global counter
for _ in range(1000000):
counter += 1
# 创建两个线程
t1 = threading.Thread(target=increment)
t2 = threading.Thread(target=increment)
start = time.perf_counter()
t1.start()
t2.start()
t1.join()
t2.join()
end = time.perf_counter()
print(f“最终结果: {counter}”) # 预期200万
print(f“耗时: {end - start:.2f}秒”)
小贴士:
GIL不是Python语言特性,是CPython解释器的实现细节
PyPy和Jython等其他Python实现就没这个限制
IO密集型任务用多线程就够了,GIL影响不大
多进程来救场
要绕过GIL,最简单的招就是用多进程。每个进程都有自己独立的Python解释器,互不干扰。multiprocessing这个库简直就是为这个场景量身定做的。
from multiprocessing import Process, Value
import time
def heavy_calculation(result):
temp = 0
for i in range(50000000):
temp += i
result.value = temp
if __name__ == '__main__':
# 创建共享内存值
result1 = Value('i', 0)
result2 = Value('i', 0)
# 启动两个进程
start = time.perf_counter()
p1 = Process(target=heavy_calculation, args=(result1,))
p2 = Process(target=heavy_calculation, args=(result2,))
p1.start()
p2.start()
p1.join()
p2.join()
领取专属 10元无门槛券
私享最新 技术干货