Async and await for concurrent results in Kotlin - Time & Space Complexity
When using async and await in Kotlin, we want to know how the program's running time changes as we add more tasks to run at the same time.
We ask: How does running many tasks concurrently affect the total time?
Analyze the time complexity of the following code snippet.
import kotlinx.coroutines.*
suspend fun fetchData(id: Int): String {
delay(1000) // Simulate network delay
return "Data $id"
}
suspend fun loadAllData(ids: List): List = coroutineScope {
val deferredResults = ids.map { id -> async { fetchData(id) } }
deferredResults.awaitAll()
}
This code fetches data for each id concurrently using async, then waits for all results.
Identify the loops, recursion, array traversals that repeat.
- Primary operation: Launching async tasks for each id in the list.
- How many times: Once per id, so as many times as the list size.
Each fetchData call takes about the same time, but they run at the same time, not one after another.
| Input Size (n) | Approx. Operations |
|---|---|
| 10 | About 1 second total (all 10 run together) |
| 100 | About 1 second total (all 100 run together) |
| 1000 | About 1 second total (all 1000 run together) |
Pattern observation: Total time stays roughly the same as input grows, because tasks run concurrently.
Time Complexity: O(1)
This means the total running time does not grow with the number of tasks because they run at the same time.
[X] Wrong: "Running more async tasks always takes more total time."
[OK] Correct: Because async tasks run together, the total time depends on the longest single task, not the number of tasks.
Understanding how async and await affect time helps you explain how to handle many tasks efficiently, a useful skill in real projects.
"What if fetchData tasks had different delays? How would that affect the total time complexity?"
Practice
async function do in Kotlin coroutines?Solution
Step 1: Understand the role of
asyncasyncstarts a coroutine that runs in the background without blocking the main thread.Step 2: Differentiate from
awaitawaitwaits for the result of the background task started byasync, butasyncitself only starts the task.Final Answer:
Starts a background task that runs concurrently -> Option AQuick Check:
async = starts background task [OK]
- Confusing async with await
- Thinking async blocks the main thread
- Assuming async cancels tasks
Solution
Step 1: Identify correct async-await usage
In Kotlin,asyncreturns a Deferred object, which you then callawait()on to get the result.Step 2: Check syntax correctness
val deferred1 = async { task1() } val deferred2 = async { task2() } val result1 = deferred1.await() val result2 = deferred2.await() correctly starts two async tasks and awaits their results separately, allowing concurrency.Final Answer:
val deferred1 = async { task1() } val deferred2 = async { task2() } val result1 = deferred1.await() val result2 = deferred2.await() -> Option CQuick Check:
async returns Deferred, await gets result [OK]
- Calling await immediately after async (no concurrency)
- Using await as a standalone function
- Not storing async result before await
import kotlinx.coroutines.*
fun main() = runBlocking {
val deferred1 = async {
delay(100)
10
}
val deferred2 = async {
delay(50)
20
}
println(deferred1.await() + deferred2.await())
}Solution
Step 1: Understand async and delay behavior
Two async tasks run concurrently: one delays 100ms and returns 10, the other delays 50ms and returns 20.Step 2: Await both results and sum
Awaiting both deferreds gets 10 and 20, summing to 30, printed as output.Final Answer:
30 -> Option BQuick Check:
10 + 20 = 30 [OK]
- Assuming sequential execution ignoring concurrency
- Confusing delay times with output values
- Expecting compilation errors due to coroutines
fun main() = runBlocking {
val result = async {
delay(100)
42
}.await()
println(result)
}Solution
Step 1: Analyze async and await usage
Callingawait()immediately afterasyncwaits for the task to finish before continuing, so concurrency is lost.Step 2: Understand concurrency impact
This pattern runs the async task sequentially, blocking until completion, defeating the purpose of async concurrency.Final Answer:
Calling await() immediately after async() blocks concurrency -> Option AQuick Check:
Immediate await blocks concurrency [OK]
- Thinking immediate await keeps concurrency
- Believing delay is disallowed inside async
- Assuming runBlocking can't be main
Solution
Step 1: Understand concurrency for API calls
Starting both API calls concurrently withasyncallows them to run at the same time, saving time.Step 2: Await both results before combining
Usingawaiton both deferred results ensures you get both responses before combining them safely.Final Answer:
Start two async coroutines for each API call, then await both results before combining -> Option DQuick Check:
Async start + await both = concurrent fetch [OK]
- Running API calls sequentially losing concurrency
- Using await without async causing errors
- Not awaiting results before combining
Ready to prove it?
Pass the test and this pattern moves unknown
