Concurrency Comparisons
Side-by-side trade-offs where neither column wins. The workload, the runtime and how much correctness risk you can carry decide — and each comparison ends with the verdict that follows from that, not from a preference.
Concurrency vs parallelismThreads vs processesAsync vs threadsEvent loop vs thread poolMutex vs semaphoreOptimistic vs pessimistic concurrency controlLock-based vs lock-freeBounded vs unbounded queue
Async vs threads
Two ways to have many things in flight. Async multiplexes tasks over one thread at explicit suspension points; threads let the OS preempt anywhere. That single difference decides where your bugs are and how many concurrent operations you can afford.
| Dimension | Async tasks | Threads |
|---|---|---|
| Cost per unit in flight | A small heap object — thousands are routine | A stack, typically measured in hundreds of kilobytes |
| Where a switch can happen | Only at await — you can see every one of them | Anywhere, including mid-increment |
| Data races on plain variables | Impossible on one loop between suspension points | Possible on every unsynchronized access |
| Race conditions | Very much possible — across await boundaries | Possible everywhere |
| CPU-bound work | Stalls the entire loop and every other task on it | Preempted by the scheduler; other threads continue |
| Blocking calls | Poison — one blocking call freezes all tasks | Absorbed, at the cost of a parked thread |
| Debugging | Async stack traces, orphaned tasks, "who never resolved this?" | Thread dumps, lock cycles, timing-dependent corruption |
| Ecosystem requirement | Every library on the hot path must be non-blocking | Anything works, blocking or not |
Use Async tasks when
- Tens of thousands of concurrent I/O operations.
- The whole stack is non-blocking, or blocking parts can be offloaded.
- You want the set of possible interleavings to be small and visible.
Use Threads when
- The libraries you must use are blocking and will not change.
- Concurrency is in the hundreds, not the tens of thousands.
- Some tasks are CPU-heavy and must not stall the others.
Verdict
Async where the concurrency is large and the work is waiting; threads where the concurrency is modest or the code blocks. Most real servers end up hybrid — an async edge with a bounded thread pool for the blocking and compute-heavy parts.
Lessons behind this comparison