Python requests - threads/processes vs. IO
Interview Questions practice on Codemia
Over 8,000 real interview questions from top companies, searchable by company and role.
Introduction
When you use Python's requests library to fetch many URLs, the bottleneck is usually network waiting time, not CPU. That distinction matters because it tells you whether threads, processes, or asynchronous I/O will actually improve throughput.
requests Is Blocking but Often Fine With Threads
requests performs synchronous network I/O. While one call waits for a server response, that worker is mostly idle. For I/O-bound workloads like HTTP fetching, threads are often the simplest performance win because blocked threads release the GIL while the socket wait happens.
For a modest number of concurrent requests, this approach is usually good enough and requires minimal code changes.
When Multiprocessing Helps and When It Does Not
Processes are useful for CPU-bound work, not for ordinary HTTP waiting. If each request is followed by heavy HTML parsing, image processing, or data compression, moving the CPU-intensive part into processes can help you use multiple cores.
If the job is mostly "send request, wait, read response," multiprocessing is usually wasteful. Each process has higher startup and memory cost, and you lose the easy connection reuse that threads can get from a shared session strategy.
This pattern makes sense only after the network step if parsing dominates total runtime.
Async I/O Is a Different Model
If you want to scale to a large number of concurrent HTTP operations, asynchronous I/O is often the best model, but requests itself is not async. The usual move is to switch to an async-capable client such as httpx or aiohttp.
Async shines when you have many in-flight requests and you are willing to adopt the async programming model across the relevant code path.
Reuse Connections Before Chasing More Concurrency
Many requests programs are slow because they open a new connection for every call. Before changing concurrency strategy, use requests.Session() so HTTP connections can be pooled and reused.
In a threaded program, it is often cleaner to create one session per thread or to benchmark carefully before sharing sessions broadly. The key point is that transport-level reuse can matter as much as concurrency choice.
Choosing the Right Approach
Use threads when:
- you already have synchronous
requestscode, - the workload is mostly network waiting,
- and the number of simultaneous requests is moderate.
Use processes when:
- post-request computation is CPU-heavy,
- and multi-core parallelism matters more than shared state.
Use async I/O when:
- you need high connection counts,
- you can switch to an async HTTP client,
- and the surrounding architecture can tolerate async code.
Common Pitfalls
The biggest mistake is using multiprocessing to speed up a purely I/O-bound requests workload. It usually adds complexity without matching the real bottleneck.
Another mistake is assuming async means "faster" regardless of context. For a small script hitting a few URLs, threads may be simpler and entirely sufficient.
Developers also overlook timeouts, retries, and connection reuse. Those operational details often affect performance and reliability more than the thread-versus-async debate.
Finally, if responses are large and parsing is expensive, split the problem mentally into two stages: network I/O and CPU work. The best concurrency model may differ for each stage.
Summary
- For ordinary
requestsworkloads, threads are usually the first concurrency tool to try. - Multiprocessing is mainly for CPU-bound work, not socket waiting.
- Async I/O requires an async client such as
httpxoraiohttp, not plainrequests. - Reusing connections with
Sessionis an important optimization on its own. - Pick the model that matches the actual bottleneck instead of optimizing by habit.
Related reading
- Python retrieve several URLs via select.epoll
- Python rewrite a looping numpy math function to run on GPU
- Python run non-blocking async function from sync function
- Python synchronous pyaudio data in asynchronous code
- Python Requests throwing SSLError
- Python re.sub group number after number
- Python threading. How do I lock a thread?
- Python threads all executing on a single core
.png&w=3840&q=75)
Tackling System Design Interview Problems
A short course that equips you with the skills to approach system design interviews methodically.
Start the free courseTrack what you have practised
A free account saves your progress, solutions and study plan across every problem on Codemia.
Interview Questions practice on Codemia
Over 8,000 real interview questions from top companies, searchable by company and role.