article banner

Exercise: Experiments with dispatchers

Experiment with how dispatcher choice influences execution time when you start 100 coroutines, each of which performs the following operations:

  • CPU-intensive cpuHeavy
  • Blocking Thread.sleep(1000)
  • Suspending delay(1000)
val dispatcher = Dispatchers.IO.limitedParallelism(1) //val dispatcher = Dispatchers.Default //val dispatcher = Dispatchers.IO //val dispatcher = Dispatchers.IO.limitedParallelism(100) val operation = ::cpu1 //val operation = ::blocking //val operation = ::suspending fun cpu1() { var i = Int.MAX_VALUE while (i > 0) i -= if (i % 2 == 0) 1 else 2 } fun blocking() { Thread.sleep(1000) } suspend fun suspending() { delay(1000) }

Test the following dispatchers:

  • Dispatcher limited to 1 thread
  • Dispatchers.Default
  • Dispatchers.IO
  • Dispatcher limited to 100 threads

Test all combinations and fill the table below with the results. Then, try to explain the results.

DispatcherCPU-intensiveBlockingSuspending
1 thread
Dispatchers.Default
Dispatchers.IO
100 threads

You can use the following code to measure execution time:

suspend fun main(): Unit = measureTimeMillis { coroutineScope { repeat(100) { launch(dispatcher) { operation() println("Done $it") } } } }.let { println("Took $it") }

This problem can either be solved in the below playground or you can clone kotlin-exercises project and solve it locally. In the project, you can find code template for this exercise in coroutines/dispatcher/Experiments.kt. You can find there starting code and example usage.

Once you are done with the exercise, you can check your solution here.

Playground

import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.coroutineScope import kotlinx.coroutines.delay import kotlinx.coroutines.launch import kotlin.system.measureTimeMillis val dispatcher = Dispatchers.IO.limitedParallelism(1) //val dispatcher = Dispatchers.Default //val dispatcher = Dispatchers.IO //val dispatcher = Dispatchers.IO.limitedParallelism(100) val operation = ::cpu1 //val operation = ::blocking //val operation = ::suspending fun cpu1() { var i = Int.MAX_VALUE while (i > 0) i -= if (i % 2 == 0) 1 else 2 } fun blocking() { Thread.sleep(1000) } suspend fun suspending() { delay(1000) } suspend fun main(): Unit = measureTimeMillis { coroutineScope { repeat(100) { launch(dispatcher) { operation() println("Done $it") } } } }.let { println("Took $it") }