由于CPython具有GIL,因此不允许任何线程同时执行python代码,因此在给定进程中似乎存在线程安全性。
python线程模块Lock ()
的目的是什么?即使没有线程可以同时执行,Lock ()
在CPython中仍会出现哪些同步问题?
答案 0 :(得分:1)
GIL只确保一次只能运行一个线程。线程仍然可能在指令之间中断,而另一个线程有机会运行。因此,如果两个线程访问共享资源,则需要使用锁保护访问。
我们来看这个例子:
from threading import Thread
i = 0
def func():
global i
while i < 1000000:
i += 1
if i != i:
print("i was modified")
for _ in range(10):
Thread(target=func).start()
虽然if
条件看起来不可能是真的,但很有可能你会看到这条线被打印出来。怎么会这样?
如果您查看func
的反汇编字节码(通过从dis.dis(func)
模块调用dis
),您就可以获得:
7 0 SETUP_LOOP 51 (to 54)
>> 3 LOAD_GLOBAL 0 (i)
6 LOAD_CONST 1 (1000000)
9 COMPARE_OP 0 (<)
12 POP_JUMP_IF_FALSE 53
8 15 LOAD_GLOBAL 0 (i)
18 LOAD_CONST 2 (1)
21 INPLACE_ADD
22 STORE_GLOBAL 0 (i)
9 25 LOAD_GLOBAL 0 (i)
28 LOAD_GLOBAL 0 (i)
31 COMPARE_OP 3 (!=)
34 POP_JUMP_IF_FALSE 3
10 37 LOAD_GLOBAL 1 (print)
40 LOAD_CONST 3 ('i was modified')
43 CALL_FUNCTION 1 (1 positional, 0 keyword pair)
46 POP_TOP
47 JUMP_ABSOLUTE 3
50 JUMP_ABSOLUTE 3
>> 53 POP_BLOCK
>> 54 LOAD_CONST 0 (None)
57 RETURN_VALUE
相关指令是25和28.如果线程在这两个指令之间被中断,则另一个therad可以修改全局变量i
,并且存储的值将是不同的。