Skip to main content

Concurrency & performance

Concurrency exists to overlap waiting (I/O, locks, timers)—not because “more threads = faster.” This page summarizes model choice, failure modes, and a repeatable measurement loop.

Model comparison

ModelMechanismFitsWatch out
Threads + shared memoryOS threads, locks, cond varsCPU parallelism, fine shared stateDeadlock, false sharing, priority inversion
Coroutines / async-awaitCooperative scheduling, event loopHigh I/O concurrency (HTTP, DB)Blocking calls stall the loop
Actors / messagesMailboxes, no shared mutationDistributed, state machinesBackpressure, ordering, timeouts
Data parallelShards, map-reduce, GPUBatch, linear algebraSplit cost, memory bandwidth

Swift: async/await, Task, actors; UI state on @MainActor.
TypeScript/Node: single-threaded loop; CPU work in workers or native code.
Go: goroutines + channels; watch leaks and unbuffered deadlocks.

Correctness: three pillars

  1. Mutual exclusion: one writer (or clear RW rules) for mutable state.
  2. Visibility: writes seen by other threads (memory model; avoid cargo-cult volatile).
  3. Ordering: happens-before via locks, channel ops, atomics.
warning

Data races: unsynchronized concurrent access is undefined behavior (Rust/Swift often reject at compile time; C/C++ may not). Prefer actors and type isolation over “one more mutex.”

Performance workflow

StepActionExamples
1. Metricsp95 latency, throughput, errors, RSSSLI/SLO, product telemetry
2. LoadProduction-like QPS, payloads, cold/warm cachek6, wrk, custom scripts
3. ProfileHot functions and waitsInstruments, perf, py-spy
4. ClassifyCPU / alloc / locks / I/O / depsFlame graphs + trace spans
5. ChangeOne hypothesis at a timeBefore/after + regression tests

Fast path: remove waiting (batching, pools, cache, async I/O) before micro-optimizing CPU.

Anti-patterns

Anti-patternSymptomFix
Huge thread poolsContext-switch blow-upSize to cores + blocking ratio
Global mutable singletonsRare crashes, torn readsDI, actors, immutable snapshots
Blocking inside asyncLatency spikesDedicated await APIs, offload pool
Unbounded queuesRSS growth, latency avalanchesBackpressure, rate limits, documented drops
Premature parallelismComplexity ↑, gain ≈ 0Amdahl: profile serial bottleneck first

Architecture tie-in

  • Async boundaries need timeouts, cancellation, idempotency—see boundaries.
  • Release cadence affects tolerance for concurrency bugs—see CI/CD.