liveBook · Manning

Suspendable computation

As explained in Kotlin in Action, 2E

A suspendable computation is a computation whose execution can be paused and later resumed while preserving its logical progress.

A suspendable computation can pause at a waiting point and later continue from that point without blocking the underlying thread. In Kotlin, a coroutine is an instance of such a computation, making asynchronous work read like ordinary sequential code while the application remains available for other work. section 1.2.4 section 14.9

suspend fun processUser(credentials: Credentials) {
    val user = authenticate(credentials)                       #1
    val data = loadUserData(user)                              #2
    val profilePicture = loadImage(data.imageID)               #3
    // ...
}
 
suspend fun authenticate(c: Credentials): User { /* ... */ }   #4
suspend fun loadUserData(u: User): Data { /* ... */ }
suspend fun loadImage(id: Int): Image { /* ... */ }

Each network call may suspend `processUser`; the next line runs only after its result is available, yet the thread can handle other tasks while waiting. section 1.2.4

Suspendable computations are useful because they:

  • Avoid tying up a thread while waiting for network or I/O work. section 14.3
  • Stay cheap enough for fine-grained and short-lived concurrent tasks. section 14.3
  • Can form parent-child task structures that support cancellation and error handling. section 14.3
  • Still run on JVM threads and can use the parallelism supplied by the threading model. section 14.3

Suspension is not the same as parallelism. Concurrency lets multiple tasks make progress in intertwined execution; parallelism physically executes work at the same time. A coroutine can suspend rather than block, while dispatchers determine which thread or thread pool runs it. section 14.9

suspend fun loadAndOverlay(first: String, second: String): Image =
    coroutineScope {
        val firstDeferred = async { loadImage(first) }                  #1
        val secondDeferred = async { loadImage(second) }                #2
        combineImages(firstDeferred.await(), secondDeferred.await())    #3
    }

`async` starts two image-loading computations from one scope, and `await` collects both results before combining them. This preserves a direct expression of concurrent work. section 1.2.4

Use suspending functions from another suspending function or from within a coroutine. Builders such as `runBlocking`, `launch`, and `async` create coroutines; `withContext` can switch dispatchers when work needs a different execution context. section 14.9

How Kotlin in Action, 2E covers it

How deep it goes
Defines coroutines as suspendable computations and explains suspension, threading, hierarchy, builders, and dispatchers without detailing implementation internals.
Examples
Uses sequential user authentication and image loading, plus concurrent image overlaying with async and await.
What you can do after
Apply it via Kotlin coroutines to express waiting and concurrent tasks without blocking underlying threads.
How it connects
Connects coroutines with suspending functions, threads, structured concurrency, cancellation, exception handling, dispatchers, coroutine context, and parallelism.

Related concepts

This explainer was generated by Manning's knowledge graph from the text of Kotlin in Action, 2E. The section links point to the parts of the book it draws on.