article banner

Exercise: Coroutine time measurement

In order to measure a block execution time, you defined the following function, that can measure real time on production, and virtual time in unit tests:

suspend fun measureCoroutine( body: suspend () -> Unit ): Duration { val dispatcher = coroutineContext[ContinuationInterceptor] return if (dispatcher is TestDispatcher) { val before = dispatcher.scheduler.currentTime body() val after = dispatcher.scheduler.currentTime after - before } else { measureTimeMillis { body() } }.milliseconds }

However, you found that it is not very convenient to use because it lacks a contract. Define a contract to make the following code compile:

runTest { val result: String val duration = measureCoroutine { delay(1000) result = "OK" } println(duration) // 1000 ms println(result) // OK } runBlocking { val result: String val duration = measureCoroutine { delay(1000) result = "OK" } println(duration) // 1000 ms println(result) // OK }

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 advanced/contract/MesureCoroutineTime.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.ExperimentalCoroutinesApi import kotlinx.coroutines.delay import kotlinx.coroutines.runBlocking import kotlinx.coroutines.test.TestDispatcher import kotlinx.coroutines.test.runTest import kotlin.contracts.ExperimentalContracts import kotlin.contracts.InvocationKind import kotlin.contracts.contract import kotlin.coroutines.ContinuationInterceptor import kotlin.coroutines.coroutineContext import kotlin.system.measureTimeMillis import kotlin.time.Duration import kotlin.time.Duration.Companion.milliseconds suspend fun measureCoroutine( body: suspend () -> Unit ): Duration { val dispatcher = coroutineContext[ContinuationInterceptor] return if (dispatcher is TestDispatcher) { val before = dispatcher.scheduler.currentTime body() val after = dispatcher.scheduler.currentTime after - before } else { measureTimeMillis { body() } }.milliseconds } suspend fun main() { runTest { val result: String val duration = measureCoroutine { delay(1000) result = "OK" } println(duration) // 1000 ms println(result) // OK } runBlocking { val result: String val duration = measureCoroutine { delay(1000) result = "OK" } println(duration) // 1000 ms println(result) // OK } }