From c1ba5af8c5d10a3d2f923f89b98f6ab1b394e24d Mon Sep 17 00:00:00 2001 From: Dmitry Khalanskiy <52952525+dkhalanskyjb@users.noreply.github.com> Date: Thu, 25 Apr 2024 10:49:04 +0200 Subject: [PATCH] Fix the ticker channel example giving wrong results on the website (#4109) https://play.kotlinlang.org/ of the example that's being changed here is currently unreliable: the last line is occasionally `null`. By increasing all time intervals twofold, we reduce the impact of the CPU scheduling in the constrained environment. With this change, the results are consistent across dozens of runs: Originally reported by `@PetrakovichVictoria` --- docs/topics/channels.md | 26 +++++++++---------- .../jvm/test/guide/example-channel-10.kt | 18 ++++++------- .../jvm/test/guide/test/ChannelsGuideTest.kt | 8 +++--- 3 files changed, 26 insertions(+), 26 deletions(-) diff --git a/docs/topics/channels.md b/docs/topics/channels.md index 019dae8476..6820f4c93c 100644 --- a/docs/topics/channels.md +++ b/docs/topics/channels.md @@ -576,25 +576,25 @@ import kotlinx.coroutines.channels.* //sampleStart fun main() = runBlocking { - val tickerChannel = ticker(delayMillis = 100, initialDelayMillis = 0) // create ticker channel + val tickerChannel = ticker(delayMillis = 200, initialDelayMillis = 0) // create a ticker channel var nextElement = withTimeoutOrNull(1) { tickerChannel.receive() } println("Initial element is available immediately: $nextElement") // no initial delay - nextElement = withTimeoutOrNull(50) { tickerChannel.receive() } // all subsequent elements have 100ms delay - println("Next element is not ready in 50 ms: $nextElement") + nextElement = withTimeoutOrNull(100) { tickerChannel.receive() } // all subsequent elements have 200ms delay + println("Next element is not ready in 100 ms: $nextElement") - nextElement = withTimeoutOrNull(60) { tickerChannel.receive() } - println("Next element is ready in 100 ms: $nextElement") + nextElement = withTimeoutOrNull(120) { tickerChannel.receive() } + println("Next element is ready in 200 ms: $nextElement") // Emulate large consumption delays - println("Consumer pauses for 150ms") - delay(150) + println("Consumer pauses for 300ms") + delay(300) // Next element is available immediately nextElement = withTimeoutOrNull(1) { tickerChannel.receive() } println("Next element is available immediately after large consumer delay: $nextElement") // Note that the pause between `receive` calls is taken into account and next element arrives faster - nextElement = withTimeoutOrNull(60) { tickerChannel.receive() } - println("Next element is ready in 50ms after consumer pause in 150ms: $nextElement") + nextElement = withTimeoutOrNull(120) { tickerChannel.receive() } + println("Next element is ready in 100ms after consumer pause in 300ms: $nextElement") tickerChannel.cancel() // indicate that no more elements are needed } @@ -610,11 +610,11 @@ It prints following lines: ```text Initial element is available immediately: kotlin.Unit -Next element is not ready in 50 ms: null -Next element is ready in 100 ms: kotlin.Unit -Consumer pauses for 150ms +Next element is not ready in 100 ms: null +Next element is ready in 200 ms: kotlin.Unit +Consumer pauses for 300ms Next element is available immediately after large consumer delay: kotlin.Unit -Next element is ready in 50ms after consumer pause in 150ms: kotlin.Unit +Next element is ready in 100ms after consumer pause in 300ms: kotlin.Unit ``` diff --git a/kotlinx-coroutines-core/jvm/test/guide/example-channel-10.kt b/kotlinx-coroutines-core/jvm/test/guide/example-channel-10.kt index 7e2b59bf1d..8867e949ab 100644 --- a/kotlinx-coroutines-core/jvm/test/guide/example-channel-10.kt +++ b/kotlinx-coroutines-core/jvm/test/guide/example-channel-10.kt @@ -5,25 +5,25 @@ import kotlinx.coroutines.* import kotlinx.coroutines.channels.* fun main() = runBlocking { - val tickerChannel = ticker(delayMillis = 100, initialDelayMillis = 0) // create ticker channel + val tickerChannel = ticker(delayMillis = 200, initialDelayMillis = 0) // create a ticker channel var nextElement = withTimeoutOrNull(1) { tickerChannel.receive() } println("Initial element is available immediately: $nextElement") // no initial delay - nextElement = withTimeoutOrNull(50) { tickerChannel.receive() } // all subsequent elements have 100ms delay - println("Next element is not ready in 50 ms: $nextElement") + nextElement = withTimeoutOrNull(100) { tickerChannel.receive() } // all subsequent elements have 200ms delay + println("Next element is not ready in 100 ms: $nextElement") - nextElement = withTimeoutOrNull(60) { tickerChannel.receive() } - println("Next element is ready in 100 ms: $nextElement") + nextElement = withTimeoutOrNull(120) { tickerChannel.receive() } + println("Next element is ready in 200 ms: $nextElement") // Emulate large consumption delays - println("Consumer pauses for 150ms") - delay(150) + println("Consumer pauses for 300ms") + delay(300) // Next element is available immediately nextElement = withTimeoutOrNull(1) { tickerChannel.receive() } println("Next element is available immediately after large consumer delay: $nextElement") // Note that the pause between `receive` calls is taken into account and next element arrives faster - nextElement = withTimeoutOrNull(60) { tickerChannel.receive() } - println("Next element is ready in 50ms after consumer pause in 150ms: $nextElement") + nextElement = withTimeoutOrNull(120) { tickerChannel.receive() } + println("Next element is ready in 100ms after consumer pause in 300ms: $nextElement") tickerChannel.cancel() // indicate that no more elements are needed } diff --git a/kotlinx-coroutines-core/jvm/test/guide/test/ChannelsGuideTest.kt b/kotlinx-coroutines-core/jvm/test/guide/test/ChannelsGuideTest.kt index c2798a3335..97aa1da836 100644 --- a/kotlinx-coroutines-core/jvm/test/guide/test/ChannelsGuideTest.kt +++ b/kotlinx-coroutines-core/jvm/test/guide/test/ChannelsGuideTest.kt @@ -113,11 +113,11 @@ class ChannelsGuideTest { fun testExampleChannel10() { test("ExampleChannel10") { kotlinx.coroutines.guide.exampleChannel10.main() }.verifyLines( "Initial element is available immediately: kotlin.Unit", - "Next element is not ready in 50 ms: null", - "Next element is ready in 100 ms: kotlin.Unit", - "Consumer pauses for 150ms", + "Next element is not ready in 100 ms: null", + "Next element is ready in 200 ms: kotlin.Unit", + "Consumer pauses for 300ms", "Next element is available immediately after large consumer delay: kotlin.Unit", - "Next element is ready in 50ms after consumer pause in 150ms: kotlin.Unit" + "Next element is ready in 100ms after consumer pause in 300ms: kotlin.Unit" ) } }