Python · The language, not just syntax

When do you use threads, processes or asyncio?

HardconcurrencythreadsmultiprocessingUpdated Oct 2026
Quiz this track

Short answer

Use threads for blocking I/O with existing synchronous libraries, processes for CPU-bound work that must use multiple cores, and asyncio for high-concurrency I/O when the stack is async-aware.

The choice follows the bottleneck. Threads share memory and are cheap to start, but the GIL serialises Python bytecode. Processes have separate memory and their own GIL, so they achieve true CPU parallelism at the cost of startup time and inter-process communication.

python
from concurrent.futures import ProcessPoolExecutor, ThreadPoolExecutor

def fetch(url):
    return client.get(url).status_code

def crunch(data):
    return sum(value * value for value in data)

with ThreadPoolExecutor(max_workers=8) as pool:
    statuses = list(pool.map(fetch, urls))

with ProcessPoolExecutor(max_workers=4) as pool:
    totals = list(pool.map(crunch, chunks))
Threads overlap network waits. Processes spread CPU work across cores, but arguments and results must be picklable.

Trade-offs

  • Threads: shared memory, lower startup cost, but locks and race conditions
  • Processes: true parallelism, isolation, but serialisation overhead and higher memory use
  • asyncio: many concurrent I/O operations in one thread, but one blocking call stalls the loop
  • Process pools need picklable payloads and careful handling of large results

Shared mutable state is the main hazard with threads. Prefer queues, immutable messages or per-thread state over locks around large critical sections. With processes, minimise data crossing the boundary because pickling and copying can dominate runtime.

Do not choose processes just because a task feels slow. Profile first. If the bottleneck is I/O, processes add overhead without improving throughput.

Follow-ups you should expect

Interviewers use these to check whether the first answer was understanding or memorisation.

  1. 1Why does a process pool achieve parallelism that a thread pool cannot?
  2. 2What kinds of objects can be sent to a process pool?
  3. 3How does asyncio differ from threading for I/O?
  4. 4What are the risks of shared mutable state across threads?

Say it in the interview

I choose based on the bottleneck. For blocking I/O with synchronous libraries I use threads, because they overlap waits and the GIL is released. For CPU-bound work I use processes so each one has its own interpreter and GIL, accepting pickling and memory overhead. For very high-concurrency I/O with async libraries I use asyncio. I profile first, because the wrong choice adds complexity without improving throughput.

Use this as a model, not a script. Saying it in your own words is what makes it survive follow-up pressure.

Related questions

Reading is step one

Now say it out loud.

Understanding an answer and delivering it under pressure are different skills. Rehearse this topic in a live Python mock interview and get scored feedback on depth, clarity and confidence.