
Scenario and Use Case
I want to write a program that performs a CPU-intensive calculation for 10 million numbers multiple times. For proof of concept, I will have it run 25 times. That would be 10M * 25 = 250 million calculations.
In GIL-enabled Python, only one thread can execute Python bytecode at a time. Even if you create many threads, they take turns running the Python interpreter.
In GIL-free Python (3.14 free-threaded build in this blog post), multiple threads can execute Python code simultaneously, making true parallelism possibleβespecially on multi-core CPUs.
In the program listed below, each thread can run Python bytecode simultaneously on different CPU cores. CPU-heavy tasks will scale with the number of cores in the computer.
Python 3.14 and threading
I will use Python 3.14 GIL-free with multithreading to run the CPU-intensive computations.
By default, Pythonβ―pre-3.14 runs with GIL-enabled, so that is not true concurrency, even when using the multithreading module.
Python code to make 25 multithreaded requests
Here's a Python program that creates 25 threads, each of which performs on 10 million computations. This program uses the Python multithreading module and simultaneously uses multiple CPU cores.
You can save it as multithreadedrequests.py
#!/usr/bin/env python3
#
# Python 3.14 GIL-free specific multithreading program to use 25 concurrent connections
# Each connection/thread performs a CPU-intensive task --
# iterate through 10 million numbers and return a simple calculation.
# This would have been limited by the GIL in previous versions,
# but now can run in parallel across multiple threads without blocking each other.
#
# Author : Arul John
# Created : 2026-04-22
# Updated : 2026-05-17
#
import sys
import threading
import time
# Vars
THREADS = 25
# A CPU-bound task that previously would have been limited by the GIL
def heavy_calculation(i, n):
result = 0
for j in range(n):
result += j * 2
print(f'π₯ THREAD {i} π₯ result = {result}')
return result
# Create and run multiple threads in parallel to perform the heavy calculation
def run_parallel_threads():
threads = []
for i in range(THREADS):
t = threading.Thread(target=heavy_calculation, args=(i, 10_000_000,))
threads.append(t)
t.start()
print(f'Started thread # {i}')
for t in threads:
t.join()
# Main
if __name__ == "__main__":
start = time.perf_counter()
run_parallel_threads()
print(f"πͺ¨ GIL enabled: {sys._is_gil_enabled()}")
print(f"πͺ¨ Completed in {time.perf_counter() - start:.2f} seconds")
Benchmarks: GIL-enabled vs GIL-free
I will run this the GIL-enabled way first.
Running this multithreaded program with GIL-enabled
python3.14 multithreadedrequests.py
Output
$ python3.14 multithreadedrequests.py
Started thread # 0
Started thread # 1
Started thread # 2
Started thread # 3
Started thread # 4
Started thread # 5
Started thread # 6
Started thread # 7
Started thread # 8
Started thread # 9
Started thread # 10
π₯ THREAD 0 π₯ result = 99999990000000
Started thread # 11
Started thread # 12
Started thread # 13
π₯ THREAD 5 π₯ result = 99999990000000
π₯ THREAD 1 π₯ result = 99999990000000
Started thread # 14
π₯ THREAD 3 π₯ result = 99999990000000
π₯ THREAD 2 π₯ result = 99999990000000
π₯ THREAD 4 π₯ result = 99999990000000
π₯ THREAD 6 π₯ result = 99999990000000
π₯ THREAD 10 π₯ result = 99999990000000
π₯ THREAD 9 π₯ result = 99999990000000
π₯ THREAD 7 π₯ result = 99999990000000
π₯ THREAD 8 π₯ result = 99999990000000
Started thread # 15
π₯ THREAD 11 π₯ result = 99999990000000
Started thread # 16
Started thread # 17
π₯ THREAD 12 π₯ result = 99999990000000
Started thread # 18
π₯ THREAD 14 π₯ result = 99999990000000
π₯ THREAD 13 π₯ result = 99999990000000
Started thread # 19
Started thread # 20
Started thread # 21
π₯ THREAD 15 π₯ result = 99999990000000
Started thread # 22
Started thread # 23
Started thread # 24
π₯ THREAD 16 π₯ result = 99999990000000
π₯ THREAD 17 π₯ result = 99999990000000
π₯ THREAD 18 π₯ result = 99999990000000
π₯ THREAD 19 π₯ result = 99999990000000
π₯ THREAD 20 π₯ result = 99999990000000
π₯ THREAD 21 π₯ result = 99999990000000
π₯ THREAD 22 π₯ result = 99999990000000
π₯ THREAD 23 π₯ result = 99999990000000
π₯ THREAD 24 π₯ result = 99999990000000
πͺ¨ GIL enabled: True
πͺ¨ Completed in 4.91 seconds
Pay attention to the last two lines.
Running this multithreaded program with GIL-disabled
Now, I will run this same program GIL-free.
python3.14t multithreadedrequests.py
Output
$ python3.14t multithreadedrequests.py
Started thread # 0
Started thread # 1
Started thread # 2
Started thread # 3
Started thread # 4
Started thread # 5
Started thread # 6
Started thread # 7
Started thread # 8
Started thread # 9
Started thread # 10
Started thread # 11
Started thread # 12
Started thread # 13
Started thread # 14
Started thread # 15
Started thread # 16
Started thread # 17
Started thread # 18
Started thread # 19
Started thread # 20
Started thread # 21
Started thread # 22
Started thread # 23
Started thread # 24
π₯ THREAD 0 π₯ result = 99999990000000
π₯ THREAD 2 π₯ result = 99999990000000
π₯ THREAD 9 π₯ result = 99999990000000
π₯ THREAD 13 π₯ result = 99999990000000
π₯ THREAD 5 π₯ result = 99999990000000
π₯ THREAD 3 π₯ result = 99999990000000
π₯ THREAD 4 π₯ result = 99999990000000
π₯ THREAD 6 π₯ result = 99999990000000
π₯ THREAD 10 π₯ result = 99999990000000
π₯ THREAD 1 π₯ result = 99999990000000
π₯ THREAD 11 π₯ result = 99999990000000
π₯ THREAD 14 π₯ result = 99999990000000
π₯ THREAD 8 π₯ result = 99999990000000
π₯ THREAD 21 π₯ result = 99999990000000
π₯ THREAD 12 π₯ result = 99999990000000
π₯ THREAD 7 π₯ result = 99999990000000
π₯ THREAD 22 π₯ result = 99999990000000
π₯ THREAD 17 π₯ result = 99999990000000
π₯ THREAD 16 π₯ result = 99999990000000
π₯ THREAD 18 π₯ result = 99999990000000
π₯ THREAD 15 π₯ result = 99999990000000
π₯ THREAD 19 π₯ result = 99999990000000
π₯ THREAD 23 π₯ result = 99999990000000
π₯ THREAD 20 π₯ result = 99999990000000
π₯ THREAD 24 π₯ result = 99999990000000
πͺ¨ GIL enabled: False
πͺ¨ Completed in 0.66 seconds
Look at the last two lines in GIL-enabled and GIL-free
Our observation
GIL-enabled
πͺ¨ GIL enabled: True
πͺ¨ Completed in 4.91 seconds
GIL-free
πͺ¨ GIL enabled: False
πͺ¨ Completed in 0.66 seconds
So, with GIL-enabled, our multithreaded program ran in 4.91 seconds, and with GIL-disabled or GIL-free, the same program ran in 0.66 seconds.
Conclusion
This is a sample Python program that uses the multithreading module in the way it is meant to be used with computers running multiple cores. If you found it useful, let me know. Thanks for reading.
Related Posts
If you have any questions, please contact me at arulbOsutkNiqlzziyties@gNqmaizl.bkcom. You can also post questions in our Facebook group. Thank you.