What is the difference between concurrency and parallelism?
Concurrency and parallelism are related but distinct concepts that are frequently conflated, even by experienced engineers.
**Concurrency** is a program structure: the ability to handle multiple tasks that are in progress simultaneously by interleaving their execution. Concurrent tasks don't need to run at the exact same instant—they can share a single CPU through context switching. The key insight is that concurrency is about *dealing with* multiple things at once, not *doing* them simultaneously. A single-core processor can run concurrent code by switching between tasks rapidly. Concurrency is primarily a solution to latency: while one task is waiting (for I/O, a lock, a network response), another can make progress.
**Parallelism** is a runtime property: multiple tasks are executing at the exact same moment on multiple physical cores or processors. Parallelism requires hardware support—multiple CPUs or cores. It's primarily a solution to throughput and CPU-bound performance: you want to do more computation per unit time by splitting work across cores.
The classic illustration from Rob Pike (Go designer): concurrency is juggling—you can only hold one ball at a time but keep multiple in the air by switching. Parallelism is having multiple jugglers, each handling their own balls simultaneously.
In practice: Python's `asyncio` is concurrent but not parallel—tasks interleave on one thread, yielding at `await` points. Python's `multiprocessing` is parallel—separate OS processes each have a core. Python's `threading` is concurrent (and, due to the GIL, rarely parallel for CPU-bound work).
A concurrent design is a prerequisite for parallelism on shared-memory systems—you must structure code to decompose work before you can run it in parallel. But concurrent code can run on a single core, while parallel execution always requires multiple.
The practical interview point: for I/O-bound workloads (web servers, database clients), concurrency alone (async I/O or threading) is sufficient and often more efficient than parallelism. For CPU-bound workloads (image processing, ML inference, data transforms), you need true parallelism via multiple processes or cores.
| Aspect | Concurrency | Parallelism |
|---|---|---|
| Definition | Multiple tasks in progress, interleaved | Multiple tasks executing simultaneously |
| Hardware requirement | Single core sufficient | Multiple cores required |
| Primary benefit | Handles latency (I/O waits) | Increases throughput (CPU work) |
| Python example | asyncio, threading | multiprocessing |
| Structure | Task switching, cooperative or preemptive | Physically simultaneous execution |
| Prerequisite relationship | Can exist without parallelism | Requires concurrent structure first |
Correctly defines concurrency as interleaved progress vs. parallelism as simultaneous execution, gives a concrete example of each, explains which is needed for I/O-bound vs. CPU-bound work.
Makes the structural vs. runtime distinction explicit, explains that concurrency is a prerequisite for parallelism, connects to Python's GIL and why threading doesn't give parallelism for CPU work, and uses a clear analogy to make it memorable.
Reading the answer is step one. Explaining it unprompted — under interview pressure — is what actually matters. Get AI-graded feedback on your answer with follow-up probes on your weak points.
Get Graded — Free Assessment