Programming Fundamentals
Concurrency & Parallelism
Concurrency is structuring a program to make progress on many tasks at once; parallelism is literally executing them at the same instant on multiple cores. The classic hazards — race conditions, deadlocks, starvation — all trace back to shared mutable state. Most application code needs concurrency for waiting on I/O, not parallelism for burning CPU.
Purpose
Concurrency and parallelism answer different questions. Concurrency is about structure: interleaving many tasks — requests, timers, downloads — so none blocks the others, even on one core. Parallelism is about execution: using several cores at physically the same time. A Node.js server is highly concurrent on a single thread; a video encoder is parallel across sixteen. The distinction decides which tools apply.
When to Use It
I/O-bound work — web servers, API aggregation, anything that spends its life waiting on the network or disk — wants concurrency: an event loop with async/await handles thousands of connections cheaply. CPU-bound work — image processing, encryption, large parses — wants parallelism: worker threads or separate processes, because an event loop blocked by computation serves nobody.
Trade-offs
The price of shared state is the whole catalogue of concurrency bugs: race conditions (outcome depends on timing), deadlocks (two tasks wait on each other forever) and starvation — all hard to reproduce and harder to debug. Message passing and immutable data avoid most of them by construction; locks solve them locally but compose badly.
Implementation
Default to sharing nothing: pass messages, return new values, keep handlers idempotent. In Node, keep the event loop free — offload CPU work to worker_threads, bound fan-out with a concurrency limit rather than a bare Promise.all, and put timeouts on every await that crosses a network. If you must lock, lock the smallest thing for the shortest time, always in the same order.