GIL требует только, чтобы интерпретатор полностью выполнил одну инструкцию байт-кода, прежде чем другой поток сможет вступить во владение. Однако нет никаких оснований предполагать, что операция приращения является одной инструкцией. Например:
>>> import dis
>>> dis.dis(compile("x=753","","exec"))
1 0 LOAD_CONST 0 (753)
3 STORE_NAME 0 (x)
6 LOAD_CONST 1 (None)
9 RETURN_VALUE
>>> dis.dis(compile("x+=1","","exec"))
1 0 LOAD_NAME 0 (x)
3 LOAD_CONST 0 (1)
6 INPLACE_ADD
7 STORE_NAME 0 (x)
10 LOAD_CONST 1 (None)
13 RETURN_VALUE
Как видите, даже эти простые операции - это не просто инструкция байт-кода. Поэтому при совместном использовании данных между потоками необходимо использовать отдельный механизм блокировки (например, threading.lock) для обеспечения согласованности данных.