Die GIL stellt nur sicher, dass immer nur ein Thread ausgeführt werden kann. Es ist immer noch möglich, dass ein Thread zwischen Anweisungen unterbrochen wird und ein anderer Thread eine Chance hat, ausgeführt zu werden. Wenn zwei Threads auf eine freigegebene Ressource zugreifen, muss der Zugriff daher durch eine Sperre geschützt werden.
Lassen Sie sich dieses Beispiel nehmen:
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()
Obwohl es wie der if
Zustand aussieht, kann unmöglich immer wahr sein, ist es eine gute Chance, dass Sie die Zeile gedruckt sehen werden. Wie kann das sein?
Wenn man sich die zerlegten Bytecode von func
suchen (durch dis.dis(func)
vom dis
Modul aufruft), das ist, was Sie bekommen:
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
Die entsprechenden Anweisungen sind 25 und 28. Wenn der Faden bekommt unterbrochen zwischen diesen beiden Anweisungen, ein anderes Therad kann die globale Variable i
ändern und die gespeicherten Werte werden unterschiedlich sein.
Wirklich nette Antwort! Vielen Dank – dylan7