Thank you, I believe you are right. I did try to make a race condition happen using += and am having a hard time. Here's my code
import threading
i = 0
def test():
global i
for x in range(1000000):
i += 1
threads = [threading.Thread(target=test) for t in range(20)]
for t in threads:
t.start()
for t in threads:
t.join()
assert i == 20000000, i
Presumably the assert should fail sometimes but I haven't been able to observe that.
a += b
takes four bytecodes: two LOAD bytecodes to put the values of a and b on the stack, an INPLACE_ADD bytecode to put the result at the top of the stack, and a STORE bytecode to store the result in the variable a. A thread switch could take place in between any two of these bytecodes, and if another thread mutated a or b or was reading the value of a or b, you would have data corruption. The GIL does not prevent this. The only way to prevent it would be to use one of the locking mechanisms provided to guard access to the a and b variables so that only one thread could access them at a time.