Python 3.13 introduces the most significant concurrency improvement in CPython's history: the ability to disable the Global Interpreter Lock (GIL). Thanks to , Python can now execute native threads in parallel — not just in theory, but in practice.
This post shares hands-on results after compiling Python 3.13 with --disable-gil, running CPU-heavy multithreading tasks, and toggling the GIL on and off at runtime. The verdict? Python threads finally scale — and in some cases, outperform multiprocessing — with no code changes.
Benchmarking: Threads vs Processes vs Serial Execution¶
To truly evaluate the GIL, I wrote the following script to simulate a real CPU workload: calculating factorials using threads, processes, and single-threaded code.
Python 3.13 with --disable-gil is not just a technical milestone — it's a practical, user-facing shift in what Python can do. For the first time, multithreaded Python isn't a theoretical dream. It's fast, predictable, and works without changing your code.
If your workloads involve concurrency, especially CPU-heavy tasks, this feature is worth adopting early.
FAQs
What is the significance of Python 3.13’s --disable-gil feature?
Python 3.13 introduces a GIL-free build option via --disable-gil, allowing native threads to execute in true parallel. This eliminates the long-standing Global Interpreter Lock bottleneck for CPU-bound multithreaded workloads.
How does performance compare with and without the GIL?
When the GIL is disabled, multithreaded CPU-bound code scales across cores, outperforming both multiprocessing (due to lower overhead) and traditional GIL-constrained threads. Serial code performance remains unaffected.
Do I need to change my code to benefit from GIL-free Python?
No. Python 3.13’s GIL-free build works without any code changes. Existing multithreaded programs can benefit immediately if the GIL is disabled at compile time and runtime.
Are there any compatibility concerns with --disable-gil?
Yes. GIL-disabled builds are not ABI-compatible with standard CPython builds. C extensions must be recompiled, and some thread-safety assumptions in third-party packages may need to be reviewed.
Is Python 3.13’s GIL-free mode production-ready?
It is currently experimental. While real-world performance improvements are promising, users should expect ongoing changes and optimizations in future versions before relying on it in critical production environments.
Like what you read? Support my work so I can keep writing more for you.
PYTHON_GIL=0 ./python3.13/bin/python3 script1.pyPython Version: 3.13.0 experimental free-threading buildGIL is currently disabledFunction 'single_threaded_task' took 4.8051 seconds to execute.Function 'multi_threaded_task' took 2.3236 seconds to execute.Function 'multi_processing_task' took 2.6521 seconds to execute.
PYTHON_GIL=1 ./python3.13/bin/python3 script1.pyPython Version: 3.13.0 experimental free-threading buildGIL is currently activeFunction 'single_threaded_task' took 4.8303 seconds to execute.Function 'multi_threaded_task' took 4.5740 seconds to execute.Function 'multi_processing_task' took 2.5155 seconds to execute.
script1.py
import sysimport sysconfigimport mathimport timefrom threading import Threadfrom multiprocessing import Processdef time_taken(func): def wrapper(*args, **kwargs): start = time.perf_counter() result = func(*args, **kwargs) end = time.perf_counter() print(f"Function '{func.__name__}' took {end - start:.4f} seconds to execute.") return result return wrapperdef compute_intensive_task(num): return math.factorial(num)@time_takendef single_threaded_task(nums): for num in nums: compute_intensive_task(num)@time_takendef multi_threaded_task(nums): threads = [] for num in nums: t = Thread(target=compute_intensive_task, args=(num,)) threads.append(t) t.start() for t in threads: t.join()@time_takendef multi_processing_task(nums): processes = [] for num in nums: p = Process(target=compute_intensive_task, args=(num,)) processes.append(p) p.start() for p in processes: p.join()def main(): print(f"Python Version: {sys.version}") gil_enabled = sys._is_gil_enabled() print("GIL is currently", "active" if gil_enabled else "disabled") nums = [300001] * 6 single_threaded_task(nums) multi_threaded_task(nums) multi_processing_task(nums)if __name__ == "__main__": main()
Learn the key differences between `removesuffix()` and `rstrip()` in Python. Avoid common pitfalls and choose the right method for precise string manipulation.
Explore the top 10 Python trends in 2025, from faster runtimes and type safety to AI, web, data, DevOps, and quantum. Stay ahead in every domain with Python.
Python 3.14 simplifies exception handling with PEP 758, letting you drop parentheses when catching multiple exceptions, cleaner, consistent, and backward-safe.
GitHub cut hosted runner prices but planned fees for self-hosted Actions, triggering backlash. The change was paused. Here’s what happened and what to expect.