Removing the GIL does not make functions thread-safe.
Thread-safety relates to this question:
If you have a data structure (say, an object, or a list) that is being modified in one thread, can another thread come along and modify it right in the middle of that calculation?
Let’s say you have a global variable x which equals 0, and two different threads attempt to increment it using this:
x += 1
If incrementing is thread-safe, then you are guaranteed that the result can only be x=2 after the two threads have incremented it. Thread safety guarantees that the only way those two threads can increment x looks like this:
- thread A locks x, so nothing else can touch it;
- thread A reads the value of x, and gets 0;
- thread A adds 1 to the value, giving 1;
- thread A writes 1 to x;
- thread A unlocks x, so other threads can use it;
- thread B locks x;
- thread B reads the value of x, and gets 1;
- thread B adds 1 to the value, giving 2;
- thread B writes 2 to x;
- and thread B unlocks x.
Of course the locks and unlocks aren’t free, that takes time, and it also means that thread B has to wait for thread A to finish, which slows it down. So thread-safety isn’t cheap.
But without thread-safety, you can have this:
- thread A reads the value of x, and gets 0;
- thread B reads the value of x, and gets 0;
- thread A adds 1 to the value, giving 1;
- thread A writes 1 to x;
- thread B adds 1 to the value, giving 1;
- thread B writes 1 to x.
So now you have a bug where two threads have both tried to increment x, both think they have done so, but x only equals 1 instead of 2.
Welcome to the Quadrant Of Hell: