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

Python3.10与旧版本无锁多线程累加结果差异原因咨询

Python3.10多线程累加无竞态现象原因解析

这个现象本质是CPython 3.10对字节码执行的GIL切换逻辑做了隐式优化,没有出现在官方更新日志的核心改动条目中,是因为该改动属于字节码调度性能优化的附带调整,不属于GIL架构层面的正式变更。

基础原理回顾

Python中对全局变量的a += 1操作会拆解为3个独立的字节码执行步骤:

  1. 从内存加载变量a的当前值
  2. 对加载的值执行+1运算
  3. 将计算结果存回变量a的内存地址
    只要GIL在这3个步骤执行过程中被切换到其他线程,就会出现竞态条件,导致累加结果丢失,这就是Python3.9版本的运行表现符合预期的原因。

3.10版本的核心改动

Python3.10引入了自适应的GIL切换阈值机制:

  • 对于无IO操作、字节码序列极短的纯计算逻辑,默认会延后GIL的切换时机,直到当前线程的时间片完全耗尽再释放GIL
  • 你提供的代码循环体仅包含a += 1这个极短的纯计算操作,在3.10的默认调度策略下,每个线程启动后会直接跑完100万次完整循环才释放GIL,不会在循环执行过程中被其他线程抢占,相当于10个线程串行完成了累加操作,自然不会出现竞态,结果恰好等于10000000。

注意:该表现只是特定场景下调度策略导致的巧合,不代表Python3.10解决了多线程竞态问题。如果累加逻辑中加入任意IO操作、循环体复杂度提升、或者手动调整GIL切换间隔,依然会出现竞态,无锁访问共享变量的安全风险依然存在。

验证方法

你可以在Python3.10环境中运行下方修改后的代码,强制触发GIL频繁切换,即可复现和3.9版本一致的竞态问题:

import threading
import sys

# 把GIL切换间隔调到极小值,强制线程频繁切换
sys.setswitchinterval(0.000001)

a = 0
threads = []

def x():
    global a
    for i in range(1_000_000):
        a += 1

for _ in range(10):
    thread = threading.Thread(target=x)
    threads.append(thread)
    thread.start()

for thread in threads:
    thread.join()

print(a)
assert a == 10_000_000

内容的提问来源于stack exchange,提问作者Zada Zorg

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.09.26 09:15:03