The GIL and its implications on locking
The GIL is a global mutex acquired when running a Python program. Execution of a bytecode is atomic but different threads may acquire the GIL in between bytecode execution.
The statement n += 1
will compile to multiple lines of bytecode and context switch might happen in between. Multiple threads doing this operation will be racing despite the presence of the GIL.
Also note that the GIL can be released during IO operations and on calls to C functions