Skip to content

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

PointConcurrencyParallelism
MeaningMany tasks are in progress during the same periodMany tasks run at exactly the same instant
CPU cores neededWorks even with 1 coreNeeds 2 or more cores
Main goalDon't waste time while waiting; stay responsive; serve many usersFinish heavy calculations faster
Best forI/O-bound work: database, files, web APIs, networkCPU-bound work: calculations, image processing, data crunching
C# toolsasync/await, Task.WhenAll, Task.WhenAnyParallel.For, Parallel.ForEach, PLINQ, Task.Run
Threads used while waitingOften none (the thread is released)Every running task keeps a thread busy
ExampleA Web API handling 1000 requests that each wait for SQL ServerResizing 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 networkasync/await (concurrency)
Calculating with the CPU on a lot of dataParallel / PLINQ (parallelism)
Calculating in a desktop app, and the UI must not freezeawait Task.Run(...) (moves the CPU work off the UI thread)
Calling many APIs with a limit on how many at onceParallel.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: use Parallel or Task.Run.