Ways to run code at the same time
Threads, processes, a pool from concurrent.futures, or asyncio. Whether the program waits on the network or works the CPU decides which.
First ask what is the program waiting for?
- It mostly waits on the network or disk (downloading pages,
calling APIs) → concurrency helps. A
ThreadPoolExecutoris the least code;asynciowith aTaskGroupscales to thousands of connections when your libraries are async. - It's busy doing arithmetic → threads won't speed it up on a
standard build, because of the GIL. Use processes
(
ProcessPoolExecutor), or NumPy, which does the work in compiled code. - You only have a few slow calls → keep it sequential. It's simpler to read, test and debug.
The free-threaded build of CPython removes the GIL, so threads can then run Python code in parallel too, but most programs don't need it.
Choosing
Section
Sequential, concurrent, parallel
Waiting at the same time is different from working at the same time.
Threads and processes
Section
Threads
Good for waiting; shared data needs a lock.
Section
Processes
Real parallelism for CPU work, at the cost of copying data between them.
Section
concurrent.futures
One pool interface for both, with submit, map and as_completed.
Section
The GIL and free threading
Why CPU-bound threads don't speed up on a standard build.
asyncio
Section
Coroutines, async and await
await hands control back to the event loop while you wait.
Section
Tasks and TaskGroups
Start several coroutines at once and wait for them all.
Section
async in practice
Timeouts, limits on how many run at once, and never calling blocking code inside async.