Python多线程中CPU Time大于Wall Time的原因探究
疑问:Python多线程下CPU总时间为何超过墙钟时间?
我编写了一段单进程多线程的Python代码,通过计时器运行:
import random import threading import hashlib a = "".join([chr(ord('a') + random.randint(1, 20)) for _ in range(50_000_000)]) def sum_part(i): part = a[i * 20_000_000: (i+1) * 20_000_000] size = 1_000_000 splits = [part[j: j + size] for j in range(0, len(part), size)] hashes = [hashlib.sha1(bytes(k, "utf-8")).hexdigest() for k in splits] return "".join(hashes) def calc_split(): threads = [threading.Thread(target=sum_part, args=[i]) for i in range(2)] for t in threads: t.start() for t in threads: t.join()
得到如下计时结果:
CPU times: user 118 ms, sys: 36.7 ms, total: 155 ms Wall time: 110 ms
按我的理解,Python的GIL应该限制同一时间只有一个CPU线程执行Python字节码,但这里CPU总时间(155ms)却超过了墙钟时间(110ms)——这种情况在C++多线程里很正常,但GIL的存在不该让Python出现这种情况吧?我忽略了什么?
核心原因:GIL在执行C扩展代码时会主动释放
你看到的CPU总时间超过墙钟时间,本质是因为代码中的hashlib.sha1()属于C实现的扩展模块:这类底层耗时操作执行时,Python会自动释放GIL,允许其他线程同时占用CPU资源。
具体细节:
- 当线程进入
hashlib.sha1()的计算逻辑时,GIL被释放,另一个线程可以立刻启动自己的哈希计算,两个线程的CPU时间会并行累积,最终总和超过实际流逝的墙钟时间。 - 你代码里的字符串切片、列表推导等纯Python字节码操作,确实受GIL限制只能单线程执行,但这些操作的耗时占比极低,对整体计时结果影响很小。
- 系统时间(sys:36.7ms)主要来自字符串转字节、内存拷贝等系统调用,这类操作同样会让线程暂时释放GIL,进一步增加总CPU时间的累积。
简言之:GIL只限制Python字节码的并行执行,对于底层用C实现的耗时操作,Python会放开GIL允许真正的多CPU并行,这就是你看到CPU总时间超过墙钟时间的关键原因。
内容的提问来源于stack exchange,提问作者sygi
相关产品推荐
相关产品推荐

