Python单线程与主线程性能差异及多线程锁性能异常疑问
Python多线程与GIL相关性能异常解析
实验背景与现象
我在测试Python的threading模块时,遇到了几个和预期不符的性能现象,以下是具体实验细节:
实验1:单线程主线程 vs 单线程子线程
测试代码:
import threading import time import multiprocessing target_count = int(100e6) mutex = threading.Lock() def thread_fn(thread_count): y = 0 for i in range(target_count // thread_count): y += 1 x = 0 start = time.time() for i in range(target_count): x += 1 end = time.time() print(f"single thread time: {(end - start) * 1000}ms") thread_count = 1 trds = [] start = time.time() for i in range(thread_count): t = threading.Thread(target=thread_fn, args=(thread_count, )) t.start() trds.append(t) for i in range(thread_count): trds[i].join() end = time.time() print(f"{thread_count} threads time: {(end - start) * 1000}ms")
运行结果:
single thread time: 9375.770568847656ms
1 threads time: 5802.408456802368ms
疑问:主线程和子线程都是单线程执行相同量级的累加操作,预期耗时相近,但实际子线程快了近40%,这是代码错误还是GIL导致的?
实验2:8线程+无意义全局锁
修改thread_fn并设置thread_count=8:
def thread_fn(thread_count): y = 0 with mutex: for i in range(target_count // thread_count): y += 1
运行结果:
single thread time: 10064.738273620605ms
8 threads time: 6456.046581268311ms
疑问:原本以为加了全局锁会让线程串行执行,额外的锁开销会让速度更慢,但实际反而比单线程快,这是为什么?
实验3:8线程无锁
使用最初的thread_fn,设置thread_count=8:
运行结果:
single thread time: 10910.805225372314ms
8 threads time: 13055.136442184448ms
疑问:8线程无锁反而比单线程慢,这又是什么原因?
现象原因解析
1. 单线程主线程 vs 子线程的性能差异
这和GIL调度、Python字节码执行优化直接相关:
- 主线程执行的是全局变量累加,Python对全局变量的访问需要从全局字典查找,而子线程操作的是局部变量,局部变量存在栈帧的快速访问区,执行效率更高。
- 另外,子线程的函数代码结构更规整,解释器能对其做更多优化(比如循环展开、局部变量缓存),而主线程的顶层代码可能伴随额外的解释器后台开销,进一步拉大了耗时差距。
2. 8线程加锁反而更快
核心是减少了GIL的频繁切换开销:
- 无锁多线程场景下,Python默认每执行100字节码就会释放GIL,多个线程会频繁争夺GIL,带来大量上下文切换、缓存失效的额外开销,反而抵消了任何可能的收益。
- 加全局锁后,每个线程会持有GIL直到整个循环执行完毕,8个线程串行执行各自的循环,但仅需要8次锁的获取/释放操作,总开销远小于频繁切换GIL的消耗,因此整体耗时比单线程还低。
3. 8线程无锁比单线程慢
这是典型的GIL竞争导致的开销膨胀:
- 你的任务是纯CPU密集型,Python多线程无法利用多核(GIL限制同一时刻只有一个线程执行Python字节码),反而因为频繁的GIL释放与争夺,导致CPU在多个线程间来回切换,额外消耗了大量资源,最终总耗时超过单线程。
内容的提问来源于stack exchange,提问作者yufusuf
相关产品推荐
相关产品推荐

