Async coroutine builder in Kotlin - Time & Space Complexity
When using async coroutine builders, it's important to understand how the program's work grows as you start more asynchronous tasks.
We want to know how the time to complete changes when we launch many async operations.
Analyze the time complexity of the following code snippet.
import kotlinx.coroutines.*
fun main() = runBlocking {
val n = 10
val deferredList = (1..n).map { i ->
async {
delay(100L) // simulate work
i * 2
}
}
val results = deferredList.awaitAll()
println(results)
}
This code launches n async coroutines that each wait a bit and then return a value. It collects all results at the end.
Identify the loops, recursion, array traversals that repeat.
- Primary operation: Launching
nasync coroutines inside a map loop. - How many times: Exactly
ntimes, once per item.
Each async coroutine runs independently, so the total work grows with how many coroutines you start.
| Input Size (n) | Approx. Operations |
|---|---|
| 10 | 10 async tasks launched |
| 100 | 100 async tasks launched |
| 1000 | 1000 async tasks launched |
Pattern observation: The number of async tasks grows directly with n, so the work grows linearly.
Time Complexity: O(n)
This means the total time to launch and wait for all async tasks grows in a straight line as you add more tasks.
[X] Wrong: "Async coroutines always run instantly and don't add to total time."
[OK] Correct: Even though async tasks run concurrently, starting and waiting for many tasks still takes more time as you add more tasks.
Understanding how async tasks scale helps you write efficient concurrent programs and explain your reasoning clearly in interviews.
What if we changed delay(100L) to a CPU-heavy calculation inside each async block? How would the time complexity change?
Practice
async coroutine builder do in Kotlin?Solution
Step 1: Understand async behavior
Theasyncbuilder starts a coroutine that runs in the background without blocking the main thread.Step 2: Recognize the return type
It returns aDeferredobject which holds the future result of the background task.Final Answer:
Starts a background task and returns a Deferred result -> Option AQuick Check:
async = background task + Deferred [OK]
- Thinking async blocks the main thread
- Confusing async with launch which returns Job
- Assuming async runs only on main thread
Solution
Step 1: Identify correct async syntax
Theasyncbuilder is called with a lambda block:async { ... }.Step 2: Check each option
val result = async { compute() } correctly usesasync { compute() }. Options B, C, and D misuse parentheses or operators.Final Answer:
val result = async { compute() } -> Option BQuick Check:
async uses curly braces for lambda [OK]
- Using parentheses instead of curly braces
- Trying to call async like a function with dot notation
- Using arrow syntax incorrectly
import kotlinx.coroutines.*
fun main() = runBlocking {
val deferred = async {
delay(100)
42
}
println("Result: ${deferred.await()}")
}Solution
Step 1: Understand async and await
Theasyncblock runs a coroutine that delays 100ms then returns 42. Theawait()waits for this result.Step 2: Print the awaited result
Theprintlnprints "Result: " plus the awaited value 42.Final Answer:
Result: 42 -> Option CQuick Check:
await() returns 42 after delay [OK]
- Printing Deferred object instead of awaited value
- Forgetting to call await()
- Expecting immediate result without delay
fun main() = runBlocking {
val deferred = async {
delay(100)
10 / 0
}
println(deferred.await())
}Solution
Step 1: Analyze the async block
The async block performs10 / 0, which causes a division by zero error.Step 2: Understand exception propagation
The exception is thrown whenawait()is called, as it waits for the async result.Final Answer:
Division by zero causes ArithmeticException at await() -> Option AQuick Check:
Exceptions in async appear on await() [OK]
- Thinking async can't be inside runBlocking
- Assuming delay() is invalid in async
- Ignoring exceptions thrown inside async block
fun main() = runBlocking {
val deferred1 = async { 10 }
val deferred2 = async { 20 }
val sum = ???
println(sum)
}Solution
Step 1: Understand how to get results from Deferred
Each async returns a Deferred. To get the actual value, callawait()on each.Step 2: Sum the awaited results
Usedeferred1.await() + deferred2.await()to get the sum of both results.Final Answer:
val sum = deferred1.await() + deferred2.await() -> Option DQuick Check:
Sum = await both Deferreds [OK]
- Trying to add Deferred objects directly
- Using non-existent get() method
- Calling await() as a standalone function
Ready to prove it?
Pass the test and this pattern moves unknown
