Why Is Python So Slow? An In‑Depth Look at GIL, Interpretation, Dynamic Typing, and JIT
The article explains why CPython often runs slower than compiled or JIT‑enabled languages by examining the Global Interpreter Lock, the interpreted nature of Python, its dynamic typing, alternative runtimes, and practical optimisation techniques for improving performance.
Python is extremely popular across DevOps, data science, web development, and security, yet it lacks any speed advantage compared to compiled languages. The article investigates why CPython can be two to ten times slower than alternatives.
Three common reasons are cited: the Global Interpreter Lock (GIL), the fact that Python is an interpreted language, and its dynamic typing system. The author asks which factor has the greatest impact.
GIL – Modern CPUs have multiple cores, and operating systems schedule work using threads. CPython protects its reference‑counting memory manager with a global lock, allowing only one thread to execute Python bytecode at a time, which severely limits parallel CPU‑bound workloads.
If an application is single‑threaded, the GIL has no effect; removing it would not speed up the code. However, for I/O‑bound multithreaded programs the GIL becomes a contention point, as illustrated by a diagram from David Beazley’s “Visualizing the GIL”.
Interpretation – Running a script involves reading, lexical analysis, parsing, compilation to bytecode, and then interpreting that bytecode. Unlike Java or C#, which use JIT compilation to optimise hot code paths, CPython executes bytecode directly, resulting in slower execution.
Java and .NET compile source to an intermediate language and then JIT‑compile hot spots at runtime, allowing aggressive optimisation. CPython lacks a JIT, though projects like PyPy provide one and can be several times faster.
Dynamic typing – In static languages, variable types are known at compile time, enabling the compiler to generate efficient machine code. Python’s dynamic typing requires runtime type checks on every variable access, making optimisation difficult.
Example of Python’s dynamic variable reassignment:
a = 1
a = "foo"Because the type can change, the interpreter must manage reference counts and perform type checks, adding overhead.
Alternative runtimes mitigate some of these issues: PyPy’s JIT is faster than CPython, Jython removes the GIL by mapping Python threads to Java threads, and JavaScript, while single‑threaded, uses an event‑loop model to avoid GIL‑like bottlenecks.
To analyse CPython’s performance, the author demonstrates building CPython with DTrace support:
wget https://github.com/python/cpython/archive/v3.6.6.zip
unzip v3.6.6.zip
cd v3.6.6
./configure --with-dtrace
makeand then running a DTrace script:
sudo dtrace -s toolkit/
.d -c '../cpython/python.exe script.py'The resulting trace shows function‑call flow and highlights where time is spent.
Conclusion: Python’s slowness stems mainly from its dynamic nature and the GIL, which together hinder optimisation. For CPU‑bound workloads, consider using PyPy (JIT), Cython (static typing), or alternative runtimes, while I/O‑bound programs can benefit from async patterns or multiple interpreter processes.
Qunar Tech Salon
Qunar Tech Salon is a learning and exchange platform for Qunar engineers and industry peers. We share cutting-edge technology trends and topics, providing a free platform for mid-to-senior technical professionals to exchange and learn.
How this landed with the community
Was this worth your time?
0 Comments
Thoughtful readers leave field notes, pushback, and hard-won operational detail here.