As an aside, there is currently a PEP that will allow for better concurrency __without__ removing the GIL, [PEP554](https://www.python.org/dev/peps/pep-0554/)
and a larger project overall for multi-core support, which is (hopefully) being included in 3.9 [Multi-core](https://github.com/ericsnowcurrently/multi-core-python)
Also, check out the SharedMemory objects[1] in 3.8. For my own use cases, this goes a long way toward making me no longer care about the GIL. I'd rather work on multiprocessing code than multithreaded code any time, and if you can easily share objects across processes, then the GIL isn't relevant to anything I'm working on.
[1] https://docs.python.org/3/library/multiprocessing.shared_mem...
If you want to do this in a more performant way you should be looking at a different language.
People talk about the GIL as if it’s just some drawback that could be removed and everything would be faster. There is a very good reason why it’s there.
It doesn't do that though. The GIL protects interpreter internals. It doesn't make Python code thread-safe, although it does make various operations atomic:
* native calls (which doesn't release the GIL) * individual bytecode instructions (which don't call into more python code)
The latter can make it seem like it magically protects your code, but even a simple method call is at least 3 instructions (LOAD_FAST, LOAD_METHOD and CALL_METHOD). Each instruction is atomic and the method call will be if it's a native call (e.g. dict.get) but that's it, the entire call itself is not atomic and you could thread-switch between LOAD_FAST and LOAD_METHOD, or LOAD_METHOD and CALL_METHOD.
It does not. What it does is create a bigger trap, because the code looks to be working in more testing situations, and will be more difficult to debug when it starts failing.
Threads may still be switched between instructions every sys.setswitchinterval milliseconds so every instruction boundary is still a potential thread switch point, leading to all the issues described by Glyph in his Unyielding essay: https://glyph.twistedmatrix.com/2014/02/unyielding.html
https://www.youtube.com/watch?v=P3AyI_u66Bw
See also Swift for another language whose implementation has performance issues caused by ubiquitous atomic reference counting.
There are other paths for improving performance that Python is embrancing: asyncio provides considerable performance gains to IO bound apps, and memory-sharing between processes allows for relatively cheap sidestep for those who find threads too slow for their use-case.