Async Models — Notes#
Structured concurrency#
Tie child tasks to a parent scope so cancellation, errors, and lifetimes are predictable.
coroutineScope {
val a = async { fetchA() }
val b = async { fetchB() }
a.await() + b.await()
}
// if either throws, both are cancelled; scope returns or throws.
Available in Kotlin, Swift, Java 21 (StructuredTaskScope), Python asyncio.TaskGroup.
Thread-per-request still works#
With Java virtual threads and a fast runtime, you can write straight-line blocking code and let the runtime multiplex on a few OS threads. Often the simplest answer for a microservice.
Watch for these#
- Don't mix sync and async in a hot path (
asyncio.runinside a sync handler). - Avoid global executors for unbounded work; bound parallelism per dependency.
- Channels with unbounded buffers are pretend-backpressure; bound them.
Refs#
- "Notes on structured concurrency, or: Go statement considered harmful" — Nathaniel Smith.
- Java Concurrency in Practice (still relevant; virtual threads add a chapter).
- Go memory model + goroutines paper.
- "Reactive Streams" spec (reactivestreams.org).
- Joe Armstrong: "Programming Erlang" (actors).