Coroutines: Simple Asynchronous Code
The problem with threads
Blocking a thread while waiting for network or disk wastes resources, and callback-based async code becomes deeply nested and hard to follow. Kotlin coroutines let you write asynchronous code that reads like ordinary sequential code, while running without blocking threads.
suspend functions
A function marked suspend can pause and resume without blocking the thread it runs on. It can only be called from another coroutine or suspend function:
suspend fun fetchUser(): User {
delay(1000) // suspends, does NOT block the thread
return User("Ada", 36)
}
Launching coroutines
Coroutine builders start coroutines. launch fires off work; async returns a result you await:
fun main() = runBlocking {
launch { println(fetchUser()) } // fire and forget
val a = async { fetchPrice("A") } // start concurrently
val b = async { fetchPrice("B") }
println(a.await() + b.await()) // both run in parallel
}
The two async calls run at the same time, so two one-second calls finish in about one second, not two.
Structured concurrency
Coroutines are always launched inside a scope. When the scope ends, its coroutines are cancelled automatically – you never leak background work. This is “structured concurrency”, and it is what makes coroutines safe.
Where you will use them
- Android: keep the UI responsive while loading data.
- Backend: handle many concurrent requests with few threads.
- Anywhere you would otherwise chain callbacks or block on I/O.
Key points
- Coroutines make async code read sequentially without blocking threads.
suspendfunctions can pause and resume; call them from a coroutine.launchstarts fire-and-forget work;async/awaitreturns a result.- Structured concurrency ties coroutines to a scope so nothing leaks.