kotlinintermediate
Coroutine Dispatchers and Context
Choose the right dispatcher: Default, IO, Main, Unconfined, and custom thread pools for coroutines.
kotlinPress ⌘/Ctrl + Shift + C to copy
import kotlinx.coroutines.*
import java.util.concurrent.Executors
import kotlin.system.measureTimeMillis
fun main() = runBlocking {
// Show which thread each dispatcher uses
println("--- Dispatcher Threads ---")
launch(Dispatchers.Default) {
println("Default: ${Thread.currentThread().name}")
}
launch(Dispatchers.IO) {
println("IO: ${Thread.currentThread().name}")
}
launch(Dispatchers.Unconfined) {
println("Unconfined (before): ${Thread.currentThread().name}")
delay(1)
println("Unconfined (after): ${Thread.currentThread().name}")
}
delay(100)
// Default — CPU-intensive work
println("\n--- CPU Work (Default) ---")
val cpuTime = measureTimeMillis {
val results = (1..8).map { n ->
async(Dispatchers.Default) {
// Simulate CPU work
var sum = 0L
repeat(10_000_000) { sum += it }
sum
}
}.awaitAll()
println("Computed ${results.size} results")
}
println("CPU time: ${cpuTime}ms")
// IO — blocking I/O operations
println("\n--- IO Operations ---")
val ioTime = measureTimeMillis {
val files = (1..20).map { i ->
async(Dispatchers.IO) {
delay(100) // simulate file/network I/O
"File-$i content"
}
}.awaitAll()
println("Read ${files.size} files")
}
println("IO time: ${ioTime}ms (parallel!)")
// withContext — switch dispatcher
println("\n--- withContext ---")
suspend fun fetchAndProcess(): String {
// IO for network call
val data = withContext(Dispatchers.IO) {
println(" Fetching on: ${Thread.currentThread().name}")
delay(100)
"raw-data"
}
// Default for CPU processing
val processed = withContext(Dispatchers.Default) {
println(" Processing on: ${Thread.currentThread().name}")
data.uppercase()
}
return processed
}
println("Result: ${fetchAndProcess()}")
// Custom dispatcher
println("\n--- Custom Dispatcher ---")
val customDispatcher = Executors.newFixedThreadPool(2) { r ->
Thread(r, "custom-pool").apply { isDaemon = true }
}.asCoroutineDispatcher()
val customResults = (1..4).map { i ->
async(customDispatcher) {
println(" Task $i on: ${Thread.currentThread().name}")
delay(50)
"result-$i"
}
}.awaitAll()
println("Custom results: $customResults")
customDispatcher.close()
// limitedParallelism (Kotlin 1.6+)
println("\n--- Limited Parallelism ---")
val limited = Dispatchers.IO.limitedParallelism(2)
val limitedTime = measureTimeMillis {
(1..6).map { i ->
async(limited) {
println(" Limited task $i on: ${Thread.currentThread().name}")
delay(100)
}
}.awaitAll()
}
println("Limited time: ${limitedTime}ms (6 tasks, 2 at a time)")
// CoroutineContext elements
println("\n--- Context Elements ---")
val context = Dispatchers.Default + CoroutineName("my-coroutine")
launch(context) {
println("Name: ${coroutineContext[CoroutineName]?.name}")
println("Job: ${coroutineContext[Job]}")
println("Dispatcher: ${coroutineContext[ContinuationInterceptor]}")
}
delay(100)
}Use Cases
- Choosing optimal dispatcher for workload type
- Thread pool management for I/O vs CPU
- Context switching between dispatchers
Tags
Related Snippets
Similar patterns you can reuse in the same workflow.
kotlinintermediate
Coroutines — launch, async, and Structured Concurrency
Write concurrent code with Kotlin coroutines: launch, async/await, structured concurrency, and dispatchers.
Best for: Parallel API calls in backend services
#kotlin#coroutines
kotlinintermediate
Flow — Reactive Streams with Coroutines
Build reactive pipelines with Kotlin Flow: emit, collect, transform, combine, and error handling.
Best for: Streaming data processing pipelines
#kotlin#flow
kotlinadvanced
Channels — Producer-Consumer with Coroutines
Communicate between coroutines with Channels: produce, actor pattern, fan-out/fan-in, and select.
Best for: Producer-consumer patterns in coroutines
#kotlin#channels
kotlinadvanced
Coroutine Mutex and Shared Mutable State
Safely manage shared state across coroutines: Mutex, atomic operations, and actor-based state.
Best for: Thread-safe counters and accumulators
#kotlin#coroutines