Careeroza
async and await
Getting a Result
async starts a coroutine that returns a value. It gives back a Deferred<T> (a future). Call await() to suspend until the value is ready.
Sequential: |--price 300ms--|--stock 300ms--| ≈ 600 ms
async/await: |--price 300ms--|
|--stock 300ms--| ≈ 300 msSequential vs Concurrent
Example
Two independent calls. With async they run at the same time.
import kotlinx.coroutines.*
import kotlin.system.measureTimeMillis
suspend fun getPrice(): Int { delay(300); return 499 }
suspend fun getStock(): Int { delay(300); return 12 }
fun main() = runBlocking {
val seq = measureTimeMillis {
val price = getPrice()
val stock = getStock()
println("Sequential: price=$price stock=$stock")
}
val conc = measureTimeMillis {
val price = async { getPrice() }
val stock = async { getStock() }
println("Concurrent: price=${price.await()} stock=${stock.await()}")
}
println("Sequential took >= 600 ms: ${seq >= 600}")
println("Concurrent took < 550 ms: ${conc < 550}")
}Output
Sequential: price=499 stock=12 Concurrent: price=499 stock=12 Sequential took >= 600 ms: true Concurrent took < 550 ms: true
awaitAll and Lazy async
Example
awaitAll waits for a list of Deferred. CoroutineStart.LAZY starts only when you call start() or await().
import kotlinx.coroutines.*
suspend fun rating(shop: String): Double {
delay(100)
return shop.length / 2.0
}
fun main() = runBlocking {
val shops = listOf("Dominos", "KFC", "Haldiram")
val ratings = shops.map { shop -> async { shop to rating(shop) } }.awaitAll()
ratings.forEach { (shop, r) -> println("$shop -> $r") }
val lazy = async(start = CoroutineStart.LAZY) {
println("Lazy job running")
42
}
println("Lazy not started yet")
println("Lazy result: ${lazy.await()}")
}Output
Dominos -> 3.5 KFC -> 1.5 Haldiram -> 4.0 Lazy not started yet Lazy job running Lazy result: 42
Rules
- Use
asynconly when you need a result and want concurrency. For a single call, just call the suspend function. - Always
await()a Deferred, otherwise its exception may be lost or crash the scope. async { }.await()right away is pointless: it is the same as calling the function directly.
Exercise: Three suspend functions each take 200 ms: loadBanner(), loadOffers(), loadCart(). Load all three concurrently and print the results. The whole thing should take about 200 ms.
Show answer
import kotlinx.coroutines.*
suspend fun loadBanner() = run { delay(200); "Diwali Sale" }
suspend fun loadOffers() = run { delay(200); listOf("10% off", "Free delivery") }
suspend fun loadCart() = run { delay(200); 3 }
fun main() = runBlocking {
val banner = async { loadBanner() }
val offers = async { loadOffers() }
val cart = async { loadCart() }
println("${banner.await()} | ${offers.await()} | cart=${cart.await()}")
}