Moore’s Law and Python’s flawed logic
When language architects designed Python, they couldn’t conceive of a world where computers had more than one core.
In the 1980s and 1990s, software engineers bet heavily on Moore’s Law, which asserts that the number of transistors on an integrated circuit would double every two years. The corollary is that speed would too.
Taking this rice on a chessboard scenario to its logical, exponential conclusion achieves effectively infinite CPU speeds in a relatively short period of time.
Guided by this logic, Python inventor Guido van Rossum architected all of Python’s multithreading capabilities around the fatally flawed assumption that computers of the future would have only a single, cheap, infinitely fast CPU.
Python’s Global Interpreter Lock (GIL) was built with the assumption that all operations would occur on this single core. Computers, phones or micro-devices with more than one CPU simply wasn’t a consideration.
Of course, increasingly fast CPUs was not the direction computer hardware took. Instead of faster CPUs, chip designers shrunk the CPU and embedded multiple cores on a chip.
“Suddenly there was all this pressure about ‘Do things in parallel,’ and that’s where the solution we had in Python didn’t work,” said Python creator Guido van Rossum on the Lex Fridman podcast. “That’s the moment the GIL became infamous.”
That’s why, more than 30 years after Python’s invention, a multithreaded Python app that runs on an enterprise server with 256 cores leaves 255 of those cores sitting idle.
Python can’t thread across cores.
Python apps can do a multithreading, but those threads can’t run across cores. It all happens on a single, solitary CPU, no matter how many CPUs exist in the system.
Concurrency in Python
Python takes a unique approach to the concept of concurrency and parallelism. Multithreaded Python applications don’t perform true parallel computing. Instead, they just create the illusion of parallelism.
To achieve this, Python schedules a thread to run for a few CPU cycles, and then interrupts that thread to allow another thread to run. Multiple Python threads divvy up all the available scheduling slots on a single CPU.
If the processor is fast enough, this creates the sensation that multiple processes are running in parallel, even though everything is serial.
Here is van Rossum again from the aforementioned podcast, explaining the logic behind the creation of Python’s multithreading libraries: “We’ll provide something that looks like threads, and as long as you only have a single CPU on your computer — which most computers at the time did — it feels just like threads.”
Python parallelism is an illusion
Python supports multithreading, but those threads all run serially on the same CPU. Nothing happens in parallel. All Python applications are CPU-bound.
The inability to thread across cores is a fundamental flaw in the architecture of the Python platform, permanently baked into the the platform since the GIL was invented almost 30 years ago.
Developers have been trying to fix the GIL ever since, to no avail.
Even an embarrassing backwards compatibility break between Python 2 and Python 3 wasn’t enough to address the issue. It’s a fundamental flaw that Python may never be able to correct.
Architects for more modern programming languages such as Java and C# understood from the days of their inception that the future of computer hardware would be multicore machines.
Long before Java’s official release in 1996, its architects provided APIs that enabled programs to thread across an infinite number of cores. What was inconceivable to the inventors of Python was a core concept behind the design of the Java Virtual Machine.
Every modern programming language supports threading across cores. Python likely never will.
How do you fix Python’s GIL?
So what can Python developers do to address the flawed GIL and Python’s multithreading mistake? Not much.
Supporters have invested thousands of hours and millions of dollars to create various incompatible Python-like libraries in an attempt to address the mistakes of Python’s past.
These expensive endeavors have led to a great deal of fragmentation in the world of Python, where many Python applications that are deployed to production or used with language models can’t actually run on a standard installation of Python.
This fragmentation has created an existential crisis in the Python community. After all, if the Python code you write is incompatible with the Python code other people write, and everyone’s code will fail to run on the standard Python platform, can you really call any of the incompatible code ‘Python?’
Several projects aim to replace the GIL with a multithreaded core, but those projects actually make single threaded Python apps run slower. This is a real problem given the fact that Python applications already run 500%-1000% slower that a similarly coded Java application.
Python recently introduced PEP 703, a proposal to make the GIL optional in future Python releases. However, it is unclear if that could be implemented without severely damaging Python’s interoperability with its most popular third-party libraries. It’s unlikely that libraries written for the standard GIL would work when integrated into a multi-threaded system.
Removing the GIL from CPython, the most commonly used Python implementation, would likely cause further fragmentation in an already heavily fragmented landscape.
Python and Project Mojo
One of the newest attempts to end industry fragmentation caused by the proliferation of new, incompatible flavors of Python is yet another new flavor of Python named Mojo.
Project Mojo, spearheaded by some of the greatest minds in the Python community, is a superset of Python.
Can Mojo fix Python?
This promising new project hopes to accomplish the following:
- Add multi-core multithreading to Python.
- Add true strong typing capabilities to Python.
- Greatly improve the performance of Python.
Fixing Python is a daunting task, but if everything goes according to plan by 2026, through Project Mojo, Python developers will have all of the features, functionality and runtime performance that Java devs have enjoyed since the JDK was released in 1996.
Python vs Java
If you’re a Python dev who can’t wait until 2026 for strong typing and multicore threading support, there are other options.
One of Python’s strengths is its ability to invoke code written in more modern programming languages. Most of the big data science libraries written in Python are just lightweight wrappers that call other languages such as Julia or C under the covers. It’s those other languages that do the real work.
If you are a software engineer and you need true multithreading capabilities in your Python programs, you could write your threaded apps in Java, and then just have the Python code invoke the Java code when it’s time to do some heavy lifting.
Or you could just write your programs in Java to begin with. That might save you a lot of headaches.