Search code examples
kotlinkotlinx.coroutines

Difference between Kotlin TickerModes


I'm having trouble understanding the difference between Kotlin ticker channel TickerMode.FIXED_DELAY and TickerMode.FIXED_PERIOD. I've played with both, but I'm unable to draw inferences from their behavior. I've also read the example in the docs. I would be grateful for a clearer explanation, with an illustration of each.


Solution

  • As you can find in coroutines sources the difference is that FIXED_PERIOD is more sophisticated and gets into account the fact the receiver cannot keep up and adjust the delay before next invocations of send. This can be tricky to demonstrate though, because you need to measure time a receiver spends waiting for a next tick.

    P.S. Note that this functionality is marked as obsolete, i.e. "the design of the corresponding declarations has serious known flaws and they will be redesigned in the future." In this case the reason is that it isn't integrated with structured concurrency.

    fun main() = runBlocking {
        println("\nFIXED_PERIOD")
        val tickerPeriodMode = ticker(100, 0, mode = TickerMode.FIXED_PERIOD)
        consumer(tickerPeriodMode)
    
        println("\nFIXED_DELAY")
        val tickerDelayMode = ticker(100, 0, mode = TickerMode.FIXED_DELAY)
        consumer(tickerDelayMode)
    }
    
    private suspend fun CoroutineScope.consumer(ticker: ReceiveChannel<Unit>) {
        val job = launch {
            var i = 0
            while (isActive) {
                val waitTime = measureTimeMillis {
                    ticker.receive()
                }
                print("[%4d ms]".format(waitTime))
    
                if (i++ == 1) {
                    delay(150)
                    println(" adding extra 150ms delay")
                } else
                    println(" going ahead")
            }
        }
        delay(1_000L)
        job.cancel()
        ticker.cancel() // indicate that no more elements are needed
    }
    

    Output

    FIXED_PERIOD
    [   1 ms] going ahead
    [  91 ms] adding extra 150ms delay
    [   0 ms] going ahead
    [  46 ms] going ahead
    [ 100 ms] going ahead
    [ 102 ms] going ahead
    [  98 ms] going ahead
    [ 100 ms] going ahead
    [  99 ms] going ahead
    [ 100 ms] going ahead
    [ 100 ms] going ahead
    
    FIXED_DELAY
    [   0 ms] going ahead
    [ 105 ms] adding extra 150ms delay
    [   0 ms] going ahead
    [ 101 ms] going ahead
    [ 100 ms] going ahead
    [ 103 ms] going ahead
    [ 103 ms] going ahead
    [ 101 ms] going ahead
    [ 101 ms] going ahead
    [ 105 ms] going ahead