尝试在Python的不同变体中重现竞争条件。以下是一个例子:
import threading, time
count = 0
def counter():
global count
c = count # 100 потоков одновременно изменили переменную c, присвоив ей значение count + 1, то есть 0+1 = 1
time.sleep(0.1) # потоки заснули
count = c + 1 # Потоки проснулись и просто присвоили переменной count значение 0+1 100 раз.
print(count) # печать count после повторного присвоения единицы.
for t in range(100):
thr = threading.Thread(target=counter)
thr.start()
(修改)
这里100个线程进入函数,给变量counter
赋值,然后睡眠0.1秒。在睡眠状态下,线程会释放GIL,这就是它们随后尝试同时增加的原因。然而,问题不在于线程捕获相同的状态。事实上,在给定的例子中,变量 count 不能以任何方式改变,因为变量始终等于 1,并且每个线程进入第 135 行,只是将2 分配给该变量,这是始终的事实的结果。这里没有竞争条件——GIL 成功阻止多个线程获取锁。我们得到以下输出:count
c
count = c + 1
count = 0
c
count
count = 2
#...
# 1
# 1
# 1
# 1
# 1
# 1
# 1
# 1
然后我尝试稍微改变一下这个功能:
import threading, time
count = 0
def counter():
global count
time.sleep(0.1)
count = count + 1
print(count)
for t in range(100):
thr = threading.Thread(target=counter)
thr.start()
与前一种情况相比,这里唯一的区别是,我们不是创建中间变量,而是count
用其自身增加它。除此之外,一切都一样——100 个线程进入该函数,休眠 0.1 秒,这会导致GIL被释放,并且变量会增加count = count + 1
。但是,竞争条件并没有发生!结论:
#...
# 94
# 95
# 96
# 97
# 98
# 99
# 100
变量count等于100,为什么会出现这种情况?看起来增量操作 += 是原子的。也就是说,可以假设在这个例子中,由于字节码级别操作的原子性,GIL 不允许多个线程同时工作。