Step 1 of 5 · Reading · ~2 min
Learn
Coroutines
Coroutines are Kotlin's lightweight async primitive. Cooperative, structured, and orders of magnitude cheaper than threads.
A coroutine is suspended with suspend functions:
import kotlinx.coroutines.*
suspend fun fetchUser(id: Int): User {
delay(100) // suspend, doesn't block thread
return database.getUser(id)
}
suspend functions can only be called from other suspend functions, OR from a coroutine builder that creates a scope.
Builders:
runBlocking { ... }— bridges blocking and coroutine code (use only in main / tests)launch { ... }— fire-and-forget, returns aJobasync { ... }— returnsDeferred<T>(like Promise)withContext(ctx) { ... }— switch dispatcher mid-coroutine
fun main() = runBlocking {
val user = async { fetchUser(1) }
val settings = async { fetchSettings(1) }
println("${user.await()} : ${settings.await()}")
}
Both fetches run in parallel. await() yields until ready.
Dispatchers decide what thread runs the coroutine:
Dispatchers.Default— CPU-bound work; pool sized to coresDispatchers.IO— blocking I/O; pool sized largerDispatchers.Main— UI thread (Android/Swing/JavaFX)Dispatchers.Unconfined— runs on whatever thread suspended (use rarely)
Structured concurrency — coroutines launched in a scope are automatically cancelled if the scope ends. No leaked tasks.
coroutineScope {
launch { task1() }
launch { task2() }
// both finish before this block returns
// if either fails, both are cancelled
}
This is Kotlin's killer feature over Java's CompletableFuture: cancellation propagation.
What this grader actually has
Everything above is real Kotlin, but kotlinx.coroutines is a separate
library, not part of the language or the standard library. This platform's
Kotlin grader ships the stdlib only, so import kotlinx.coroutines.* fails
here with unresolved reference: kotlinx, and runBlocking, launch,
async and delay are unavailable with it.
suspend itself is a language feature and does compile. The stdlib's
kotlin.coroutines package gives you the low-level machinery the library is
built on:
import kotlin.coroutines.Continuation
import kotlin.coroutines.EmptyCoroutineContext
import kotlin.coroutines.startCoroutine
suspend fun answer(): Int = 42
fun main() {
var out: Int? = null
val block: suspend () -> Int = { answer() }
block.startCoroutine(Continuation(EmptyCoroutineContext) { r -> out = r.getOrThrow() })
println(out) // 42
}
That is what runBlocking is underneath, minus the event loop that makes
delay and real parallelism work. Use it for the exercise; use
kotlinx.coroutines in a project where you can add the dependency.
Discussion
Ask a question, share an insight, or help someone who’s stuck.
Sign in to post a comment or reply.
Loading…