You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.19 16:24:59