3 ms·
Just look at the bytecode. >>> import dis >>> def increment_counter(): ... counter = counter + 1 >>> dis.dis(increment_counter) 2 0 L
by oefrha 5y ago
Just look at the bytecode.
>>> import dis
>>> def increment_counter():
... counter = counter + 1
>>> dis.dis(increment_counter)
2 0 LOAD_FAST 0 (counter)
2 LOAD_CONST 1 (1)
4 BINARY_ADD
6 STORE_FAST 0 (counter)
8 LOAD_CONST 0 (None)
10 RETURN_VALUE
A data race looks like
LOAD_FAST from thread 1 begins
STORE_FAST from thread 2 begins
memory is partially overwritten
LOAD_FAST from thread 1 finishes (got partially written garbage)
STORE_FAST from thread 2 finishes
This is not a data race:
LOAD_FAST from thread 1
LOAD_FAST from thread 2
STORE_FAST from thread 1
STORE_FAST from thread 2
There's no LOAD_FAST + STORE_FAST "transaction" here, GIL has no such guarantee.
Edit: You also need to realize that in Python, that BINARY_ADD can be anything:
import time
class SlowCounter(int):
def __add__(self, other):
time.sleep(1)
return SlowCounter(super().__add__(other))
counter = SlowCounter()
counter += 1
The GIL isn't going to wait around for the __add__.