Skip to content

Commit

Permalink
Fix the ticker channel example giving wrong results on the website (#…
Browse files Browse the repository at this point in the history
…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:
<https://pl.kotl.in/uCa-60j43>

Originally reported by `@PetrakovichVictoria`
  • Loading branch information
dkhalanskyjb authored Apr 25, 2024
1 parent 2430d9a commit c1ba5af
Show file tree
Hide file tree
Showing 3 changed files with 26 additions and 26 deletions.
26 changes: 13 additions & 13 deletions docs/topics/channels.md
Original file line number Diff line number Diff line change
Expand Up @@ -576,25 +576,25 @@ import kotlinx.coroutines.channels.*

//sampleStart
fun main() = runBlocking<Unit> {
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
}
Expand All @@ -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
```

<!--- TEST -->
Expand Down
18 changes: 9 additions & 9 deletions kotlinx-coroutines-core/jvm/test/guide/example-channel-10.kt
Original file line number Diff line number Diff line change
Expand Up @@ -5,25 +5,25 @@ import kotlinx.coroutines.*
import kotlinx.coroutines.channels.*

fun main() = runBlocking<Unit> {
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
}
Original file line number Diff line number Diff line change
Expand Up @@ -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"
)
}
}

0 comments on commit c1ba5af

Please sign in to comment.