Threads, processes, and when async is wrong
Threads, processes, and when async is wrong
Async has one job: let a process do other work while it waits. Two kinds of work defeat it. The first is a library that blocks, a synchronous SDK, a driver with no async version, a file read on a slow disk, where there is an await-shaped wait but no await to express it. The second is computation, parsing a forty-page PDF attachment, tokenising a corpus, computing embeddings locally, where nothing is waiting at all and the processor is the bottleneck.
For the first, a thread. Hand the blocking call to a worker thread and await the result; the loop stays free while the thread waits. For the second, a process. Hand the computation to a worker process on another core and await that; the loop stays free while the other core works. And since Python 3.14 there is a third option for the second case: the free-threaded build, where threads run Python code in parallel without the global interpreter lock, which changes the arithmetic for CPU-bound work.
Continue reading
Pro unlocks every video lesson, the full notes and runnable code across the Python with AI course, from the language itself to agents, MCP, Langfuse and deployment.