When you fan out into a list of Deferreds, what does awaitAll do, and how does it behave on failure compared to awaiting in a loop?
answer
- awaitAll = wait all, ordered List<T>
- fails fast on first failure
- loop awaits in order, slower to surface
- results in input order, not completion
- map { async }.awaitAll() pattern
basics
~10 sawaitAll waits for every Deferred in a list and returns all their results as a list. If any one fails, awaitAll fails fast immediately instead of waiting for the slower remaining ones.
solid answer
~40 sawaitAll is an extension (on Collection<Deferred<T>> and as a vararg) that suspends until all the given Deferreds complete and returns List<T> in input order. Its key advantage over a manual `deferreds.map { it.await() }` loop is failure timing: awaitAll **fails fast** — the moment any Deferred fails, awaitAll throws that exception right away rather than awaiting earlier-in-the-list slow ones first. Under structured concurrency inside coroutineScope, a child failure also cancels its siblings, so a failure in one fan-out task tears down the rest and propagates. Use it for parallel decomposition over a collection: `val results = items.map { async { process(it) } }.awaitAll()`. Order of results matches the list, regardless of which finished first.
code
kotlin · 3 linessuspend fun fetchPages(urls: List<String>): List<String> = coroutineScope {
urls.map { url -> async { httpGet(url) } }.awaitAll()
}go deeper
Knows awaitAll returns a list of all results from a list of Deferreds.
Explains fail-fast vs loop ordering and input-order results; uses the map+async+awaitAll pattern.
Connects fail-fast to structured cancellation of siblings and chooses supervisorScope/per-task catching for partial results.
Designs fan-out with concurrency caps, error-aggregation strategy, and clear all-or-nothing vs best-effort contracts.
## What `awaitAll` does `awaitAll` waits for a **collection of `Deferred`** to all complete and returns their results as a `List<T>` in the **same order as the input** (not completion order). Two overloads exist: - `Collection<Deferred<T>>.awaitAll(): List<T>` - `awaitAll(vararg deferreds: Deferred<T>): List<T>` ```kotlin suspend fun processAll(items: List<Item>): List<Result> = coroutineScope { items .map { item -> async { process(item) } } // fan out, all start eagerly .awaitAll() // fan in, ordered results } ``` ## awaitAll vs. a manual loop A hand-written `deferreds.map { it.await() }` awaits in **list order**. If the third item fails fast but the first is slow, the loop is still stuck on the first `await()` and only surfaces the failure later. **`awaitAll` fails fast**: it throws as soon as *any* Deferred completes exceptionally, no matter its position in the list. ## Failure + structured concurrency Inside `coroutineScope { }`, the `async` children are structured. If one child throws: 1. The failing child completes exceptionally. 2. The parent `coroutineScope` is cancelled, which **cancels the sibling Deferreds**. 3. `awaitAll` (and the enclosing `coroutineScope`) rethrows the original exception. So one bad task tears down the whole fan-out — usually what you want for all-or-nothing work. If you need partial results, wrap each task to catch its own exception (e.g., return a sealed result) or use `supervisorScope`. ## Ordering guarantee Results come back in **input order**, decoupled from which coroutine finished first. This makes zipping results back to inputs trivial. ## Key APIs/keywords - `awaitAll()` — fail-fast, ordered fan-in - `List<Deferred<T>>` produced by `map { async { } }` - `coroutineScope` / `supervisorScope` to control failure propagation
- Are results returned in completion order or input order?Input order. awaitAll preserves the order of the original collection regardless of which Deferred finished first.
- How would you get partial results instead of all-or-nothing?Catch exceptions inside each async (return a Result/sealed type), or run under supervisorScope so one failure doesn't cancel siblings.
saying these in an interview costs you the question
- Saying results come back in completion order
- Claiming awaitAll waits for all even after one fails (it fails fast)
- Not realizing a child failure cancels siblings under coroutineScope
- Using awaitAll when partial results are needed without supervisorScope or per-task catching