Disabling GIL - Unleashing the True Power of Python
Python 3.13
Unleashing Parallel Power
Introduction
Python is finally getting rid of its major limitation, the Global Interpreter Lock (GIL), which it has had since 1991. Before explaining what the GIL is, let's understand how computers and programming languages were designed in the 1990s.
In the 1990s, computers were not focused on speed or running multiple applications at the same time. They were designed to complete tasks efficiently. There were no computers with multiple CPU cores or processors, so programs from that time prioritized memory efficiency over speed. High speed needs both software and hardware to work together. Without the right hardware, making super-fast software would have been pointless.
Given the hardware limits back then, Python focused on memory efficiency, robustness, and simplicity rather than multi-threading, which allows multiple tasks to run at the same time. Since Python is a fully dynamic or interpreted language, its developers added the Global Interpreter Lock (GIL) to manage and process object references efficiently within a single thread.
Global Interpreter Lock (GIL)
When it comes to multi-threading, Python behaves a bit weird. Let's understand this with a small example.
In the world of computers, programs are like me and my brother trying to play the game. The Global Interpreter Lock (GIL) is like the rule that only allows one, either me or my brother (or thread), to play the game (or execute Python bytecode) at a time.
GIL is a rule that allows only one thread at a time to run the Python bytecode. It protects access to Python objects, preventing multiple threads from executing Python bytecode simultaneously in a single process.
Performance Impact
This causes performance limitations of multi-threading in CPU-bound tasks. Note that CPU-bound tasks are the tasks that rely a lot on CPU rather than IO operations. Mathematical computations, compression and decompression of files, and compilation of programs are a few examples.
Why GIL & What is the Advantage?
1. Memory Management
CPython uses reference counting as a primary mechanism for memory management. Every Python object has a reference count, which tracks how many references point to the object. When the count drops to zero, the memory occupied by the object is freed.
"Without the GIL, multiple threads could simultaneously modify the reference count of an object, leading to race conditions and potentially corrupting the reference count, resulting in memory leaks or crashes."
2. Simplicity and Safety
The GIL makes the Python interpreter easier to implement because it removes the need for detailed locking around shared resources. This simplifies maintenance and development, especially with Python's dynamic typing and complex object model.
Let us understand with an example
import threading
counter = 0
iterations = 1000000
def increment_counter():
global counter
for _ in range(iterations):
counter += 1
# Create two threads
thread1 = threading.Thread(target=increment_counter)
thread2 = threading.Thread(target=increment_counter)
# Start both threads
thread1.start()
thread2.start()
# Wait for both threads to finish
thread1.join()
thread2.join()
print(f"Final counter value: {counter}")Expected Outcome
If Python didn't have the GIL, you might expect the final value to be 2 million. However, without proper locking, you risk race conditions and lost increments.
Actual Outcome (With GIL)
Python prevents both threads from modifying the counter simultaneously. While this prevents race conditions, the threads aren't truly parallel; they are interleaved.
Why not remove GIL completely?
Removing the Global Interpreter Lock (GIL) from Python has been a topic of discussion for many years. While it seems like an obvious solution, the decision is not straightforward.
Slower Single-Threaded Performance
Fine-grained locking introduces overhead, slowing down the majority of Python programs that only use one thread.
Fine-Grained Locking Complexity
Implementing and maintaining locks across all Python data types is highly complex and prone to subtle bugs.
Backward Compatibility
Many C extensions and libraries assume the presence of the GIL. Removing it could break the vast ecosystem.
Library Performance
Libraries like NumPy and pandas rely on the GIL for simplicity and could suffer degradation.
Why remove it now?
The answer is simple. The growing need for AI and machine learning computations, along with the availability of powerful hardware like CPUs and GPUs, led to the decision. This change improves multi-threading, which greatly speeds up these computations and CPU operations.
Python 3.13 Release Candidate
Python 3.13 includes the initial experimental removal of the GIL. If you use the GUI installer, configure it to include "free-threaded binaries (experimental)".
Metrics & Results
import time
import threading
from time import perf_counter
def sum_of_squares(n):
return sum(i * i for i in range(n))
def sum_of_squares_partial(start, end, result, index):
result[index] = sum(i * i for i in range(start, end))
def run_single_threaded(n):
start_time = perf_counter()
result = sum_of_squares(n)
end_time = perf_counter()
print(f"Time taken: {end_time - start_time:.4f} seconds")
def run_multi_threaded(n, num_threads):
chunk_size = n // num_threads
threads = []
results = [0] * num_threads
start_time = perf_counter()
for i in range(num_threads):
start = i * chunk_size
end = start + chunk_size if i != num_threads - 1 else n
thread = threading.Thread(target=sum_of_squares_partial, args=(start, end, results, i))
threads.append(thread)
thread.start()
for thread in threads:
thread.join()
end_time = perf_counter()
print(f"Time taken: {end_time - start_time:.4f} seconds")| Metric | GIL Enabled (3.13) | GIL Disabled (3.13) | Python 3.12 |
|---|---|---|---|
| Single-threaded | 50.31s | 57.41s | 54.33s |
| Multi-threaded | 58.77s | 21.84s (Winner) | 60.17s |
Summary
Removing the GIL can greatly boost performance in multi-threading, the concept that has changed the way we compute. Just imagine if Python ran without the GIL. It could greatly speed up Machine Learning, AI models, and improve performance in the Pandas library.
While removing the GIL is not easy and requires a major redesign, I believe it is worth it because of the benefits it offers in the AI field.
Until then, your friend here, Hemachandra, is signing off…
For more courses, visit my website here.
Stay ahead of the curve
Get the latest technical insights on Python, Security, and Cloud Architecture delivered to your inbox.