Profile    Mohammed Shiroz Status   Loading  
Logo
Share This
Back to blog
Filter by:
Tags
//Article title

Concurrency vs Parallelism, Explained With a Kitchen

About Post

One cook can serve a three-course dinner for six people. Not by moving faster than humanly possible, but by never standing still while the water boils.

That's concurrency. And it's the reason a single-threaded Node.js process can handle thousands of open connections, while a perfectly good PHP endpoint can still be slow for reasons that more servers won't fix.

Developers use "concurrent" and "parallel" as if they were the same word. They're not, and mixing them up leads to fixes that don't fix anything. Rob Pike put the difference in one line that's worth memorising: concurrency is about dealing with lots of things at once; parallelism is about doing lots of things at once.

Let's walk into a kitchen and see what that means.

Scene 1: one cook, one thing at a time

A single cook makes pasta. Puts the water on. Stands there, watching it, until it boils. Cooks the pasta. Only then starts chopping the salad.

That's sequential work. Nothing is wrong with the food; the problem is all the time spent waiting. And in software, most of the waiting looks exactly like this: a database query, an HTTP call to a payment gateway, a file being read. The CPU does almost nothing while it waits.

Scene 2: one cook, juggling

Same cook, smarter. Water on. While it heats, chop the salad. Pasta in. While it cooks, make the dressing. Check the pot, drain, serve.

Still one pair of hands. At any single moment, the cook is only doing one thing. But several dishes are in progress at the same time, and the waiting overlaps instead of adding up. That's concurrency without parallelism.

This is how Node.js works. One main thread runs your JavaScript, and when you start an I/O operation, Node hands it off and moves on to the next task until the result comes back. The trick only works if nobody hogs the cook:

// One after another: total time is the sum of both waits
const user = await getUser(id);
const orders = await getOrders(id);

// Concurrently: both requests in flight, total is roughly the longer wait
const [sameUser, sameOrders] = await Promise.all([getUser(id), getOrders(id)]);

The first version isn't wrong, it's just a cook watching water boil. If the second call doesn't depend on the first, there's no reason to wait.

Scene 3: four cooks, four orders

Now hire three more cooks. Each takes an order and cooks it start to finish. Four dishes really are being worked on at the same instant, by different hands. That's parallelism, and it needs more than one worker: more CPU cores, processes or machines.

A typical PHP setup is this kitchen. PHP-FPM keeps a pool of worker processes, and each request gets one worker from start to finish. Queue workers are the same idea: run more of them, and more jobs are processed at the same moment. The individual cook isn't juggling, but the kitchen as a whole serves many tables.

Scene 4: the cook who blocks the kitchen

Back to our single juggling cook. A customer orders bread made from scratch, and the cook stops everything to knead dough for twenty minutes. Every other dish waits. The water boils over.

That's what CPU-heavy work does to an event loop. Resizing images, parsing a huge JSON file, hashing in a tight loop: while Node is busy calculating, it can't respond to anyone else. Concurrency helps with waiting. It does nothing for working. For real computation you need parallelism: in Node, worker threads or separate processes; in PHP, separate processes or a queue.

What this looks like in PHP

A classic slow endpoint calls three external APIs one after another. The fix isn't more servers; each request would still wait for all three in turn. The fix is overlapping the waits. Laravel's HTTP client can send them concurrently:

use Illuminate\Http\Client\Pool;
use Illuminate\Support\Facades\Http;

$responses = Http::pool(fn (Pool $pool) => [
    $pool->as('rates')->get('https://api.example.com/rates'),
    $pool->as('weather')->get('https://api.example.com/weather'),
    $pool->as('news')->get('https://api.example.com/news'),
]);

$rates = $responses['rates']->json();

And when the work is genuinely CPU-heavy, Laravel's Concurrency facade runs closures in separate PHP processes, which is true parallelism:

use Illuminate\Support\Facades\Concurrency;

[$revenue, $arrears] = Concurrency::run([
    fn () => Report::monthlyRevenue($month),
    fn () => Report::arrearsSummary($month),
]);

Starting processes has a cost, and each closure and its result has to be serialized, so this is for chunky work, not tiny tasks. For anything long-running, a queue is still the better kitchen.

Side by side

ConcurrencyParallelism
Kitchen versionOne cook, many dishes in progressMany cooks, cooking at the same instant
Helps withWaiting (I/O-bound work)Working (CPU-bound work)
Needs multiple cores?NoYes
Node.jsEvent loop, Promise.allWorker threads, child processes
PHP / LaravelHttp::pool, async libraries such as ReactPHP and AmpFPM workers, queue workers, Concurrency::run

The kitchen's hidden problems

More cooks don't scale forever. Two cooks reaching for the only good knife is a race condition, the same thing as two requests updating one balance. The single oven everyone needs is your database: add more cooks, and they just queue at the oven. And the supplier who only takes so many orders an hour is the external API with a rate limit. Parallelism moves the bottleneck; it doesn't remove it.

Diagnose before you scale: if your code is slow because it's waiting, make the waits overlap (concurrency). If it's slow because it's computing, add hands (parallelism). If it's slow because everyone needs the same oven, fix the oven.

The one-sentence version

Concurrency is a cook who never stands idle; parallelism is a kitchen with more cooks. Most web apps need far more of the first than they think, and a bit less of the second.

Where have you seen the two mixed up? My most common one is "let's add more servers" for an endpoint that's really just waiting on three API calls in a row.

Comments (0)
Leave your review

Thanks for your valuable comments. Your comments has been updated and appreciate your getting in touch...

01. About Shiroz

Mohammed Shiroz

Hi, I'm Mohammed Shiroz, a software engineer and AI enthusiast from Sri Lanka who turns ideas into intelligent, real-world solutions. With over 9 years of hands-on experience, I currently lead real estate ERP development at Kate Group, a...

03.My Projects

04. Categories

Ready To order Your Project ?

Get in Touch
Close