为何Python 3.11多线程代码无竞态条件,修改后却出现?
Python 3.11多线程竞态条件差异解析
现象描述
执行下方多线程代码时,Python 3.11中最终输出的counter值始终等于4000000(无竞态条件),但将代码里的counter += 1修改为counter += int(1)后,竞态条件立即出现,最终结果会小于预期值。
原代码:
import threading import time counter = 0 lock = threading.Lock() def increment(): global counter for _ in range(10**6): counter += 1 threads = [] for i in range(4): x = threading.Thread(target=increment) threads.append(x) for t in threads: t.start() for t in threads: t.join() print(counter)
原因解析
这是Python 3.10及以上版本新增的字节码优化导致的:
- 针对
counter += 1这类简单整数自增操作,CPython编译器会把它直接优化为单条INPLACE_ADD字节码指令。由于CPython的全局解释器锁(GIL)在执行单条字节码指令期间不会释放,这个自增操作就变成了原子性操作,多线程执行时不会出现竞态。 - 改成
counter += int(1)后,因为int(1)是一个函数调用,编译器无法将整个表达式合并为单条字节码。此时这条语句会被拆分成多个步骤:调用int(1)获取数值、加载counter当前值、执行加法运算、将结果赋值回counter。在这一系列步骤中,GIL可能会被释放,其他线程就有机会在中间阶段修改counter,进而引发竞态条件,导致最终结果小于预期。
内容的提问来源于stack exchange,提问作者RohanAlmighty
相关产品推荐
相关产品推荐

