Difference Between Concurrency and Parallelism
People often use these two words as if they mean the same thing. They don't. Once you see the difference, it becomes very easy to decide when to use async/await and when to use Parallel.
"Concurrency is about dealing with lots of things at once. Parallelism is about doing lots of things at once." — Rob Pike
The kitchen picture
- Concurrency: one chef, three dishes. The chef switches between them, and all three are in progress.
- Parallelism: three chefs, three dishes. Each chef cooks one dish at the same time.
- Both together: three chefs, ten dishes. Each chef switches between a few dishes, and the chefs work side by side.
The timeline picture
Here tasks A, B and C are shown over time. Each box is a moment when that task is actually running on a CPU core.
Concurrency (1 core, switching between tasks)
Core 1 : [A][B][A][C][B][A][C][B][C]
all three tasks are "in progress", only one runs at any instant
Parallelism (3 cores, running at the same instant)
Core 1 : [A][A][A]
Core 2 : [B][B][B]
Core 3 : [C][C][C]
three tasks really run at the same moment
Comparison table
| Point | Concurrency | Parallelism |
|---|---|---|
| Meaning | Many tasks are in progress during the same period | Many tasks run at exactly the same instant |
| CPU cores needed | Works even with 1 core | Needs 2 or more cores |
| Main goal | Don't waste time while waiting; stay responsive; serve many users | Finish heavy calculations faster |
| Best for | I/O-bound work: database, files, web APIs, network | CPU-bound work: calculations, image processing, data crunching |
| C# tools | async/await, Task.WhenAll, Task.WhenAny | Parallel.For, Parallel.ForEach, PLINQ, Task.Run |
| Threads used while waiting | Often none (the thread is released) | Every running task keeps a thread busy |
| Example | A Web API handling 1000 requests that each wait for SQL Server | Resizing 1000 photos using all 8 CPU cores |
Same goal, two different tools
Suppose we have to handle 4 items, and each item takes 1 second.
// CONCURRENCY: each item WAITS 1 second (e.g. a web API call).
// The thread is free during the wait, so 4 waits overlap: about 1 second total.
static async Task ProcessOrdersAsync(int[] orderIds)
{
var tasks = orderIds.Select(id => CallPaymentApiAsync(id));
await Task.WhenAll(tasks);
}
static async Task CallPaymentApiAsync(int orderId)
{
await Task.Delay(1000); // waiting for another server
Console.WriteLine($"Order {orderId} paid");
}
// PARALLELISM: each item CALCULATES for 1 second (CPU busy all the time).
// Four cores calculate at the same time: about 1 second total on a 4+ core machine.
static void ProcessImages(string[] images)
{
Parallel.ForEach(images, image =>
{
ResizeImage(image); // heavy CPU work
});
}
Both finish in about 1 second, but for different reasons:
- The first one is fast because the waiting overlaps. It would be fast even on a 1-core machine, and it uses almost no threads.
- The second one is fast because four cores calculate together. On a 1-core machine it would take 4 seconds.
Choosing the right one
| If your code is mostly... | Use |
|---|---|
| Waiting for a database, file, web API or network | async/await (concurrency) |
| Calculating with the CPU on a lot of data | Parallel / PLINQ (parallelism) |
| Calculating in a desktop app, and the UI must not freeze | await Task.Run(...) (moves the CPU work off the UI thread) |
| Calling many APIs with a limit on how many at once | Parallel.ForEachAsync with MaxDegreeOfParallelism (.NET 6+) |
A common mistake is to use Parallel.ForEach for web or database calls. It blocks one thread per call while it waits. For waiting work, Task.WhenAll gives the same speed while keeping threads free.
Summary
- Concurrency = dealing with many tasks at once (they take turns or overlap their waiting).
- Parallelism = doing many tasks at once (on different cores at the same instant).
- Parallelism is one way of being concurrent, but concurrency does not need parallelism.
- I/O-bound work: use
async/await. CPU-bound work: useParallelorTask.Run.