Skip to content

Threading in Python

What is a thread?

A thread is a unit of execution inside a process.

  • One process can have multiple threads.
  • Threads share the same memory of the process.

When to use threading

Threading is best for I/O-bound tasks:

  • network requests
  • reading/writing files
  • waiting on APIs

When NOT to use threading

For CPU-bound tasks (heavy computation), Python threads are limited by the GIL (Global Interpreter Lock) in CPython.

For CPU-bound parallelism, prefer:

  • multiprocessingmultiprocessing
  • native extensions

The Global Interpreter Lock (GIL)

In CPython, only one thread executes Python bytecode at a time.

Practical takeaway:

  • Threads can still improve performance when time is spent waiting (I/O).
  • Threads won’t speed up CPU-only loops significantly.

Quick demo (I/O wait simulation)

io_wait_demo.py
import time
import threading
 
 
def task(i: int) -> None:
    time.sleep(1)
    print("done", i)
 
 
threads = []
start = time.time()
 
for i in range(5):
    t = threading.Thread(target=task, args=(i,))
    t.start()
    threads.append(t)
 
for t in threads:
    t.join()
 
print("seconds:", round(time.time() - start, 2))
io_wait_demo.py
import time
import threading
 
 
def task(i: int) -> None:
    time.sleep(1)
    print("done", i)
 
 
threads = []
start = time.time()
 
for i in range(5):
    t = threading.Thread(target=task, args=(i,))
    t.start()
    threads.append(t)
 
for t in threads:
    t.join()
 
print("seconds:", round(time.time() - start, 2))

Without threads, this would take about 5 seconds; with threads it’s ~1 second (because sleep is I/O wait).

Visualize it

A thread moves through a small lifecycle — created, started, running, sometimes waiting on I/O or a lock, then finished and joined back:

diagram A thread's life mermaid
A thread is created, started, runs or waits, and finally joins back to the main thread.

The GIL means only one thread runs Python at a time — but the instant a thread waits on I/O it hands the GIL over, so another thread runs. That overlap is exactly why threading speeds up I/O-bound work (and why it doesn’t help CPU-bound work):

sketch Threads overlap during I/O waits p5.js
Only one thread runs Python at a time, but while a thread waits on I/O another runs — so I/O-bound work overlaps.

🧪 Try It Yourself

Exercise 1 – Create a Simple Thread

Exercise 2 – Join a Thread

Exercise 3 – Run Multiple Threads

If this helped you, consider buying me a coffee ☕

Buy me a coffee

Was this page helpful?

Let us know how we did