Python GIL-Free Multithreaded Program

Published May 17, 2026

Python 3.14 GIL-free program that uses multithreading

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.

Disclaimer: Our website is supported by our users. We sometimes earn affiliate links when you click through the affiliate links on our website.

Last Updated: May 17, 2026.     This post was originally written on May 11, 2026.