Lesson 16 / 25

Suspend Functions and Coroutine Builders

suspend, launch, async and runBlocking.

Suspending, not blocking

A suspend function can pause without blocking its thread, for example while waiting for network I/O, and resume later; it can only be called from another suspend function or a coroutine. The language provides suspend; the kotlinx.coroutines library provides builders. launch starts a coroutine for work without a result and returns a Job. async starts one that produces a value and returns a Deferred<T>, whose await() suspends until the result is ready. runBlocking blocks the current thread until its coroutines finish; use it only at boundaries such as main or legacy tests, never inside suspend code or on an Android main thread. delay is the suspending counterpart of Thread.sleep.

Asynchronous code that reads like sequential code

Coroutines suspend instead of blocking threads, and structured concurrency keeps their lifetimes under control.

Three ideas: suspend functions and builders, structured concurrency, dispatchers and Flow.
Figure 6.1 — Scope, child coroutines, dispatchers and a flow of values.

Two calls in parallel with async

coroutineScope waits for its children.

import kotlinx.coroutines.*

suspend fun fetchUser(id: Long): String { delay(100); return "user-$id" }    // simulated I/O
suspend fun fetchOrders(id: Long): List<String> { delay(150); return listOf("o1", "o2") }

suspend fun loadDashboard(id: Long): String = coroutineScope {
    val user = async { fetchUser(id) }          // both start concurrently
    val orders = async { fetchOrders(id) }
    "${user.await()} has ${orders.await().size} orders"
}

fun main() = runBlocking {                      // boundary between blocking and suspending
    val job = launch { delay(50); println("background work done") }
    println(loadDashboard(42))
    job.join()
}

A chef with several pans

A blocking thread is a chef staring at one pot until it boils. A coroutine lets the chef put the pot on, step away to chop vegetables, and come back when it is ready, so one chef handles many dishes.

Quick check: Which builder returns a Deferred whose result you await?

  • `runBlocking`
  • `launch`
  • `async`
  • `delay`
Answer

`async` — launch returns a Job; async returns Deferred<T>.