threading
The threading module runs OS threads in one process with shared memory. Use threads for I/O-bound overlap; guard shared mutable state with Lock, RLock, Event, and Condition.
Search across all documentation pages
The threading module runs OS threads in one process with shared memory. Use threads for I/O-bound overlap; guard shared mutable state with Lock, RLock, Event, and Condition.
import threading
counter = 0
lock = threading.Lock()
def inc() -> None:
global counter
with lock:
counter += 1When to reach for this:
threading.Timer)Event)import threading
import time
from queue import Queue
results: Queue[int] = Queue()
stop = threading.Event()
def worker(worker_id: int) -> None:
while not stop.is_set():
time.sleep(0.05)
results.put(worker_id)
threads = [threading.Thread(target=worker, args=(i,), daemon=True) for i in range(3)]
for t in threads:
t.start()
time.sleep(0.2)
stop.set()
for t in threads:
t.join(timeout=1)
print("collected", results.qsize())What this demonstrates:
Event signals graceful shutdownQueue passes results without manual lock on listjoin(timeout) avoids hanging shutdown| Type | Use |
|---|---|
| Lock | Mutual exclusion |
| RLock | Reentrant lock same thread |
| Event | One-shot or persistent flag |
| Semaphore | Limit concurrency count |
threading.local() for per-thread statewith lock: or queue.| Alternative | Use When | Don't Use When |
|---|---|---|
| asyncio | High fan-out I/O, async APIs | Blocking SDK only |
| multiprocessing | CPU parallel | Need shared memory |
| concurrent.futures | Pool abstraction | Custom thread lifecycle |
Start near concurrent blocking operations (connections), not CPU core count.
RLock when same thread re-enters guarded code (recursive helpers).
Single append is atomic in CPython but compound read-modify-write is not.
Use threading - higher level, supports locks and join.
loop.run_in_executor runs blocking code in thread pool without blocking loop.
threading.local() attributes isolated per thread - handy for request context in sync WSGI.
Use same connection per thread or check sqlite3 thread safety mode - often serial access.
Thread(name="worker-1") improves debugger and log readability.
Yes - pool amortizes thread creation cost.
Stress tests + threading.Barrier; avoid flaky timing assertions - use events.
Stack versions: This page was written for Python 3.14.0 (stable 3.14, maintenance 3.13), FastAPI 0.115+, Django 5.2, Flask 3.1, Pydantic 2, PyTorch 2.6+, pandas 2.2+, Polars 1.x, ruff 0.9+, and uv 0.6+.
Reviewed by Chris St. John·Last updated Jul 19, 2026