⚡ Concurrency & Parallelism
Threads for I/O
Use threading when you wait on the network or disk.
Threads share memory and are great for I/O-bound work. The GIL means only one thread runs Python bytecode at a time — so threads do NOT speed up CPU-bound code.
import threading
results = []
def square(n):
results.append(n * n)
threads = [threading.Thread(target=square, args=(i,)) for i in range(1, 5)]
for t in threads: t.start()
for t in threads: t.join()
print(sorted(results)) # [1, 4, 9, 16]
**Rules of thumb**
- I/O-bound (network, disk) → threads or asyncio.
- CPU-bound (math, parsing) → multiprocessing (each process has its own GIL).
- Always
.join()threads or use a context likeconcurrent.futures.ThreadPoolExecutor.
> 🧪 This topic is concept-only in the browser sandbox — Pyodide runs in a single Web Worker and cannot spawn OS threads. Try the snippet in real CPython.