CPython 和线程模块 Lock()
CPython and threading module Lock()
由于 CPython 具有 GIL,因此不允许任何线程同时执行 python 代码,因此在给定进程中似乎存在线程安全。
那么 python 线程模块 Lock ()
的目的是什么?即使没有线程可以同时执行,CPython 中仍然会出现哪些同步问题 Lock ()
可以帮助解决?
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.dis(func)
),您将得到以下内容:
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
并且存储的值会不同。
由于 CPython 具有 GIL,因此不允许任何线程同时执行 python 代码,因此在给定进程中似乎存在线程安全。
那么 python 线程模块 Lock ()
的目的是什么?即使没有线程可以同时执行,CPython 中仍然会出现哪些同步问题 Lock ()
可以帮助解决?
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.dis(func)
),您将得到以下内容:
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
并且存储的值会不同。