GIL Become Optional in Python 3.13
GIL or Global Interpreter Lock can be disabled in Python version 3.13. This is currently experimental.
What is GIL? It is a mechanism used by the CPython interpreter to ensure that only one thread executes the Python bytecode at a time.
An Experimental Feature
Python 3.13 brings major new features compared to Python 3.12 and one of them is free-threaded mode, which disables the Global Interpreter Lock, allowing threads to run more concurrently.
This is an experimental feature and if you want to try it, you can download the beta version of Python 3.13 from here.
At the time of installation, check the option “free threaded binaries(experimental)” to get the feature in Python.
Making GIL Optional in Python 3.13
The GIL will be disabled when you configure the Python with the --disable-gil
option which is nothing but a build configuration (free threading build) at the time of installation.
This will allow optionally enabling and disabling GIL using the environment variable PYTHON_GIL
which can be set to 1
and 0
respectively.
It will also provide a command-line option -X gil
which can also be set to 0
(disable) and 1
(enable).
# v3.13
# GIL disabled
python3 -X gil=0 sample.py
# GIL enabled
python3 -X gil=1 sample.py
We can also check if the current interpreter is configured with the free threading build (--disable-gil
) by using the following code.
import sysconfig
print(sysconfig.get_config_var("Py_GIL_DISABLED"))
If we run this, we’ll get either 0
which means GIL is enabled, or 1
which means GIL is disabled.
With this, we’ll also get a function that can be used to check if GIL is disabled in the running process.
import sys
sys._is_gil_enabled() # returns a boolean value
GIL Vs No GIL
Let’s see how the performance of multi-threaded programs will be affected when GIL is enabled and disabled.
We have a simple Python program (gil.py
) that computes the factorial of numbers and compares the execution time taken by single-threaded, multi-thread, and multi-process tasks. We'll run this Python program first with GIL and then without GIL.
import sys
import sysconfig
import math
import time
import threading
import multiprocessing
def compute_factorial(n):
return math.factorial(n)
# Single-threaded
def single_threaded_compute(n):
for num in n:
compute_factorial(num)
print("Single-threaded: Factorial Computed.")
# Multi-threaded
def multi_threaded_compute(n):
threads = []
# Create 5 threads
for num in n:
thread = threading.Thread(target=compute_factorial, args=(num,))
threads.append(thread)
thread.start()
# Wait for all threads to complete
for thread in threads:
thread.join()
print("Multi-threaded: Factorial Computed.")
# Multi-process
def multi_processing_compute(n):
processes = []
# Create a process for each number in the list
for num in n:
process = multiprocessing.Process(target=compute_factorial, args=(num,))
processes.append(process)
process.start()
# Wait for all processes to complete
for process in processes:
process.join()
print("Multi-process: Factorial Computed.")
def main():
# Checking Version
print(f"Python version: {sys.version}")
# GIL Status
status = sysconfig.get_config_var("Py_GIL_DISABLED")
if status is None:
print("GIL cannot be disabled")
if status == 0:
print("GIL is active")
if status == 1:
print("GIL is disabled")
numlist = [100000, 200000, 300000, 400000, 500000]
# Single-threaded Execution
start = time.time()
single_threaded_compute(numlist)
end = time.time() - start
print(f"Single-threaded time taken: {end:.2f} seconds")
# Multi-threaded Execution
start = time.time()
multi_threaded_compute(numlist)
end = time.time() - start
print(f"Multi-threaded time taken : {end:.2f} seconds")
# Multi-process Execution
start = time.time()
multi_processing_compute(numlist)
end = time.time() - start
print(f"Multi-process time taken : {end:.2f} seconds")
if __name__ == "__main__":
main()
Running gil.py
with GIL
python gil.py
Python version: 3.12.2 (tags/v3.12.2:6abddd9, Feb 6 2024, 21:26:36) [MSC v.1937 64 bit (AMD64)]
GIL cannot be disabled
Single-threaded: Factorial Computed.
Single-threaded time taken: 9.04 seconds
Multi-threaded: Factorial Computed.
Multi-threaded time taken : 8.21 seconds
Multi-process: Factorial Computed.
Multi-process time taken : 5.64 seconds
We have Python v3.12 in which there is no option to check the GIL status, so we got “GIL cannot be disabled”.
The difference is not that much between the single-threaded and multi-threaded but we can see a pretty decent difference in the case of multi-process task.
Running gil.py
without GIL
D:/SACHIN/Python13/python3.13t gil.py
Python version: 3.13.0b3 experimental free-threading build (tags/v3.13.0b3:7b41395, Jun 27 2024, 16:17:17) [MSC v.1940 64 bit (AMD64)]
GIL is disabled
Single-threaded: Factorial Computed.
Single-threaded time taken: 9.28 seconds
Multi-threaded: Factorial Computed.
Multi-threaded time taken : 4.86 seconds
Multi-process: Factorial Computed.
Multi-process time taken : 6.14 seconds
This time we have a third beta version of Python 3.13 configured with free threading build and as we can see the GIL is disabled.
But the most important part is we can see a massive difference in the performance of multi-threaded task and on the other side, some degradation can be seen in the performance of multi-process and single-threaded task.
🏆Other articles you might be interested in if you liked this one
✅Create multi-threaded Python programs using a threading module.
✅Template inheritance in Flask.
✅Difference between exec and eval in Python.
✅Create temporary files and directories using tempfile module in Python.
That’s all for now
Keep Coding✌✌