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
