blob: 48d87289dc5aa955c349c6e285ec8990d90fafab [file] [log] [blame] [view]
hadihariri7db55532018-09-15 10:35:08 +02001<!--- INCLUDE .*/example-([a-z]+)-([0-9a-z]+)\.kt
2/*
3 * Copyright 2016-2018 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
4 */
5
6// This file was automatically generated from coroutines-guide.md by Knit tool. Do not edit.
7package kotlinx.coroutines.experimental.guide.$$1$$2
8
9import kotlinx.coroutines.experimental.*
10import kotlinx.coroutines.experimental.channels.*
11-->
12<!--- KNIT ../core/kotlinx-coroutines-core/test/guide/.*\.kt -->
13<!--- TEST_OUT ../core/kotlinx-coroutines-core/test/guide/test/ChannelsGuideTest.kt
14// This file was automatically generated from coroutines-guide.md by Knit tool. Do not edit.
15package kotlinx.coroutines.experimental.guide.test
16
17import org.junit.Test
18
19class ChannelsGuideTest {
20-->
21## Table of contents
22
23<!--- TOC -->
24
Vsevolod Tolstopyatovb590aa32018-09-27 18:34:05 +030025* [Channels (experimental)](#channels-experimental)
hadihariri7db55532018-09-15 10:35:08 +020026 * [Channel basics](#channel-basics)
27 * [Closing and iteration over channels](#closing-and-iteration-over-channels)
28 * [Building channel producers](#building-channel-producers)
29 * [Pipelines](#pipelines)
30 * [Prime numbers with pipeline](#prime-numbers-with-pipeline)
31 * [Fan-out](#fan-out)
32 * [Fan-in](#fan-in)
33 * [Buffered channels](#buffered-channels)
34 * [Channels are fair](#channels-are-fair)
35 * [Ticker channels](#ticker-channels)
36
37<!--- END_TOC -->
38
39
40
41
42
43## Channels (experimental)
44
45Deferred values provide a convenient way to transfer a single value between coroutines.
46Channels provide a way to transfer a stream of values.
47
48> Channels are an experimental feature of `kotlinx.coroutines`. Their API is expected to
49evolve in the upcoming updates of the `kotlinx.coroutines` library with potentially
50breaking changes.
51
52### Channel basics
53
54A [Channel] is conceptually very similar to `BlockingQueue`. One key difference is that
55instead of a blocking `put` operation it has a suspending [send][SendChannel.send], and instead of
56a blocking `take` operation it has a suspending [receive][ReceiveChannel.receive].
57
Alexander Prendotacbeef102018-09-27 18:42:04 +030058
59<div class="sample" markdown="1" theme="idea" data-highlight-only>
60
hadihariri7db55532018-09-15 10:35:08 +020061```kotlin
Vsevolod Tolstopyatova2d80882018-09-24 19:51:49 +030062fun main(args: Array<String>) = runBlocking {
hadihariri7db55532018-09-15 10:35:08 +020063 val channel = Channel<Int>()
64 launch {
65 // this might be heavy CPU-consuming computation or async logic, we'll just send five squares
66 for (x in 1..5) channel.send(x * x)
67 }
68 // here we print five received integers:
69 repeat(5) { println(channel.receive()) }
70 println("Done!")
71}
72```
73
Alexander Prendotacbeef102018-09-27 18:42:04 +030074</div>
75
hadihariri7db55532018-09-15 10:35:08 +020076> You can get full code [here](../core/kotlinx-coroutines-core/test/guide/example-channel-01.kt)
77
78The output of this code is:
79
80```text
811
824
839
8416
8525
86Done!
87```
88
89<!--- TEST -->
90
91### Closing and iteration over channels
92
93Unlike a queue, a channel can be closed to indicate that no more elements are coming.
94On the receiver side it is convenient to use a regular `for` loop to receive elements
95from the channel.
96
97Conceptually, a [close][SendChannel.close] is like sending a special close token to the channel.
98The iteration stops as soon as this close token is received, so there is a guarantee
99that all previously sent elements before the close are received:
100
Alexander Prendotacbeef102018-09-27 18:42:04 +0300101<div class="sample" markdown="1" theme="idea" data-highlight-only>
102
hadihariri7db55532018-09-15 10:35:08 +0200103```kotlin
Vsevolod Tolstopyatova2d80882018-09-24 19:51:49 +0300104fun main(args: Array<String>) = runBlocking {
hadihariri7db55532018-09-15 10:35:08 +0200105 val channel = Channel<Int>()
106 launch {
107 for (x in 1..5) channel.send(x * x)
108 channel.close() // we're done sending
109 }
110 // here we print received values using `for` loop (until the channel is closed)
111 for (y in channel) println(y)
112 println("Done!")
113}
114```
115
Alexander Prendotacbeef102018-09-27 18:42:04 +0300116</div>
117
hadihariri7db55532018-09-15 10:35:08 +0200118> You can get full code [here](../core/kotlinx-coroutines-core/test/guide/example-channel-02.kt)
119
120<!--- TEST
1211
1224
1239
12416
12525
126Done!
127-->
128
129### Building channel producers
130
131The pattern where a coroutine is producing a sequence of elements is quite common.
132This is a part of _producer-consumer_ pattern that is often found in concurrent code.
133You could abstract such a producer into a function that takes channel as its parameter, but this goes contrary
134to common sense that results must be returned from functions.
135
arman simonyan02b33022018-10-10 22:06:04 +0400136There is a convenient coroutine builder named [produce] that makes it easy to do it right on producer side,
hadihariri7db55532018-09-15 10:35:08 +0200137and an extension function [consumeEach], that replaces a `for` loop on the consumer side:
138
Alexander Prendotacbeef102018-09-27 18:42:04 +0300139<div class="sample" markdown="1" theme="idea" data-highlight-only>
140
hadihariri7db55532018-09-15 10:35:08 +0200141```kotlin
Vsevolod Tolstopyatova2d80882018-09-24 19:51:49 +0300142fun CoroutineScope.produceSquares(): ReceiveChannel<Int> = produce {
hadihariri7db55532018-09-15 10:35:08 +0200143 for (x in 1..5) send(x * x)
144}
145
Vsevolod Tolstopyatova2d80882018-09-24 19:51:49 +0300146fun main(args: Array<String>) = runBlocking {
hadihariri7db55532018-09-15 10:35:08 +0200147 val squares = produceSquares()
148 squares.consumeEach { println(it) }
149 println("Done!")
150}
151```
152
Alexander Prendotacbeef102018-09-27 18:42:04 +0300153</div>
154
hadihariri7db55532018-09-15 10:35:08 +0200155> You can get full code [here](../core/kotlinx-coroutines-core/test/guide/example-channel-03.kt)
156
157<!--- TEST
1581
1594
1609
16116
16225
163Done!
164-->
165
166### Pipelines
167
168A pipeline is a pattern where one coroutine is producing, possibly infinite, stream of values:
169
Alexander Prendotacbeef102018-09-27 18:42:04 +0300170<div class="sample" markdown="1" theme="idea" data-highlight-only>
171
hadihariri7db55532018-09-15 10:35:08 +0200172```kotlin
173fun CoroutineScope.produceNumbers() = produce<Int> {
174 var x = 1
175 while (true) send(x++) // infinite stream of integers starting from 1
176}
177```
178
Alexander Prendotacbeef102018-09-27 18:42:04 +0300179</div>
180
hadihariri7db55532018-09-15 10:35:08 +0200181And another coroutine or coroutines are consuming that stream, doing some processing, and producing some other results.
182In the below example the numbers are just squared:
183
Alexander Prendotacbeef102018-09-27 18:42:04 +0300184<div class="sample" markdown="1" theme="idea" data-highlight-only>
185
hadihariri7db55532018-09-15 10:35:08 +0200186```kotlin
Vsevolod Tolstopyatova2d80882018-09-24 19:51:49 +0300187fun CoroutineScope.square(numbers: ReceiveChannel<Int>): ReceiveChannel<Int> = produce {
hadihariri7db55532018-09-15 10:35:08 +0200188 for (x in numbers) send(x * x)
189}
190```
191
Alexander Prendotacbeef102018-09-27 18:42:04 +0300192</div>
193
hadihariri7db55532018-09-15 10:35:08 +0200194The main code starts and connects the whole pipeline:
195
Alexander Prendotacbeef102018-09-27 18:42:04 +0300196<div class="sample" markdown="1" theme="idea" data-highlight-only>
197
hadihariri7db55532018-09-15 10:35:08 +0200198```kotlin
Vsevolod Tolstopyatova2d80882018-09-24 19:51:49 +0300199fun main(args: Array<String>) = runBlocking {
hadihariri7db55532018-09-15 10:35:08 +0200200 val numbers = produceNumbers() // produces integers from 1 and on
201 val squares = square(numbers) // squares integers
202 for (i in 1..5) println(squares.receive()) // print first five
203 println("Done!") // we are done
204 coroutineContext.cancelChildren() // cancel children coroutines
205}
206```
207
Alexander Prendotacbeef102018-09-27 18:42:04 +0300208</div>
209
hadihariri7db55532018-09-15 10:35:08 +0200210> You can get full code [here](../core/kotlinx-coroutines-core/test/guide/example-channel-04.kt)
211
212<!--- TEST
2131
2144
2159
21616
21725
218Done!
219-->
220
221> All functions that create coroutines are defined as extensions on [CoroutineScope],
Alexander Prendotacbeef102018-09-27 18:42:04 +0300222so that we can rely on [structured concurrency](https://github.com/Kotlin/kotlinx.coroutineskotlinx.coroutines/blob/master/docs/composing-suspending-functions.md#structured-concurrency-with-async) to make
hadihariri7db55532018-09-15 10:35:08 +0200223sure that we don't have lingering global coroutines in our application.
224
225### Prime numbers with pipeline
226
227Let's take pipelines to the extreme with an example that generates prime numbers using a pipeline
228of coroutines. We start with an infinite sequence of numbers.
229
230<!--- INCLUDE
231import kotlin.coroutines.experimental.*
232-->
Alexander Prendotacbeef102018-09-27 18:42:04 +0300233
234<div class="sample" markdown="1" theme="idea" data-highlight-only>
hadihariri7db55532018-09-15 10:35:08 +0200235
236```kotlin
237fun CoroutineScope.numbersFrom(start: Int) = produce<Int> {
238 var x = start
239 while (true) send(x++) // infinite stream of integers from start
240}
241```
242
Alexander Prendotacbeef102018-09-27 18:42:04 +0300243</div>
244
hadihariri7db55532018-09-15 10:35:08 +0200245The following pipeline stage filters an incoming stream of numbers, removing all the numbers
246that are divisible by the given prime number:
247
Alexander Prendotacbeef102018-09-27 18:42:04 +0300248<div class="sample" markdown="1" theme="idea" data-highlight-only>
249
hadihariri7db55532018-09-15 10:35:08 +0200250```kotlin
251fun CoroutineScope.filter(numbers: ReceiveChannel<Int>, prime: Int) = produce<Int> {
252 for (x in numbers) if (x % prime != 0) send(x)
253}
254```
255
Alexander Prendotacbeef102018-09-27 18:42:04 +0300256</div>
257
hadihariri7db55532018-09-15 10:35:08 +0200258Now we build our pipeline by starting a stream of numbers from 2, taking a prime number from the current channel,
259and launching new pipeline stage for each prime number found:
260
261```
262numbersFrom(2) -> filter(2) -> filter(3) -> filter(5) -> filter(7) ...
263```
264
265The following example prints the first ten prime numbers,
266running the whole pipeline in the context of the main thread. Since all the coroutines are launched in
267the scope of the main [runBlocking] coroutine
268we don't have to keep an explicit list of all the coroutines we have started.
269We use [cancelChildren][kotlin.coroutines.experimental.CoroutineContext.cancelChildren]
270extension function to cancel all the children coroutines after we have printed
271the first ten prime numbers.
272
Alexander Prendotacbeef102018-09-27 18:42:04 +0300273<div class="sample" markdown="1" theme="idea" data-highlight-only>
274
hadihariri7db55532018-09-15 10:35:08 +0200275```kotlin
Vsevolod Tolstopyatova2d80882018-09-24 19:51:49 +0300276fun main(args: Array<String>) = runBlocking {
hadihariri7db55532018-09-15 10:35:08 +0200277 var cur = numbersFrom(2)
278 for (i in 1..10) {
279 val prime = cur.receive()
280 println(prime)
281 cur = filter(cur, prime)
282 }
283 coroutineContext.cancelChildren() // cancel all children to let main finish
284}
285```
286
Alexander Prendotacbeef102018-09-27 18:42:04 +0300287</div>
288
hadihariri7db55532018-09-15 10:35:08 +0200289> You can get full code [here](../core/kotlinx-coroutines-core/test/guide/example-channel-05.kt)
290
291The output of this code is:
292
293```text
2942
2953
2965
2977
29811
29913
30017
30119
30223
30329
304```
305
306<!--- TEST -->
307
308Note, that you can build the same pipeline using
309[`buildIterator`](https://kotlinlang.org/api/latest/jvm/stdlib/kotlin.coroutines.experimental/build-iterator.html)
310coroutine builder from the standard library.
311Replace `produce` with `buildIterator`, `send` with `yield`, `receive` with `next`,
312`ReceiveChannel` with `Iterator`, and get rid of the coroutine scope. You will not need `runBlocking` either.
313However, the benefit of a pipeline that uses channels as shown above is that it can actually use
314multiple CPU cores if you run it in [Dispatchers.Default] context.
315
316Anyway, this is an extremely impractical way to find prime numbers. In practice, pipelines do involve some
317other suspending invocations (like asynchronous calls to remote services) and these pipelines cannot be
318built using `buildSequence`/`buildIterator`, because they do not allow arbitrary suspension, unlike
319`produce`, which is fully asynchronous.
320
321### Fan-out
322
323Multiple coroutines may receive from the same channel, distributing work between themselves.
324Let us start with a producer coroutine that is periodically producing integers
325(ten numbers per second):
326
Alexander Prendotacbeef102018-09-27 18:42:04 +0300327<div class="sample" markdown="1" theme="idea" data-highlight-only>
328
hadihariri7db55532018-09-15 10:35:08 +0200329```kotlin
330fun CoroutineScope.produceNumbers() = produce<Int> {
331 var x = 1 // start from 1
332 while (true) {
333 send(x++) // produce next
334 delay(100) // wait 0.1s
335 }
336}
337```
338
Alexander Prendotacbeef102018-09-27 18:42:04 +0300339</div>
340
hadihariri7db55532018-09-15 10:35:08 +0200341Then we can have several processor coroutines. In this example, they just print their id and
342received number:
343
Alexander Prendotacbeef102018-09-27 18:42:04 +0300344<div class="sample" markdown="1" theme="idea" data-highlight-only>
345
hadihariri7db55532018-09-15 10:35:08 +0200346```kotlin
347fun CoroutineScope.launchProcessor(id: Int, channel: ReceiveChannel<Int>) = launch {
348 for (msg in channel) {
349 println("Processor #$id received $msg")
350 }
351}
352```
353
Alexander Prendotacbeef102018-09-27 18:42:04 +0300354</div>
355
hadihariri7db55532018-09-15 10:35:08 +0200356Now let us launch five processors and let them work for almost a second. See what happens:
357
Alexander Prendotacbeef102018-09-27 18:42:04 +0300358<div class="sample" markdown="1" theme="idea" data-highlight-only>
359
hadihariri7db55532018-09-15 10:35:08 +0200360```kotlin
361fun main(args: Array<String>) = runBlocking<Unit> {
362 val producer = produceNumbers()
363 repeat(5) { launchProcessor(it, producer) }
364 delay(950)
365 producer.cancel() // cancel producer coroutine and thus kill them all
366}
367```
368
Alexander Prendotacbeef102018-09-27 18:42:04 +0300369</div>
370
hadihariri7db55532018-09-15 10:35:08 +0200371> You can get full code [here](../core/kotlinx-coroutines-core/test/guide/example-channel-06.kt)
372
373The output will be similar to the the following one, albeit the processor ids that receive
374each specific integer may be different:
375
376```
377Processor #2 received 1
378Processor #4 received 2
379Processor #0 received 3
380Processor #1 received 4
381Processor #3 received 5
382Processor #2 received 6
383Processor #4 received 7
384Processor #0 received 8
385Processor #1 received 9
386Processor #3 received 10
387```
388
389<!--- TEST lines.size == 10 && lines.withIndex().all { (i, line) -> line.startsWith("Processor #") && line.endsWith(" received ${i + 1}") } -->
390
391Note, that cancelling a producer coroutine closes its channel, thus eventually terminating iteration
392over the channel that processor coroutines are doing.
393
394Also, pay attention to how we explicitly iterate over channel with `for` loop to perform fan-out in `launchProcessor` code.
395Unlike `consumeEach`, this `for` loop pattern is perfectly safe to use from multiple coroutines. If one of the processor
396coroutines fails, then others would still be processing the channel, while a processor that is written via `consumeEach`
397always consumes (cancels) the underlying channel on its normal or abnormal completion.
398
399### Fan-in
400
401Multiple coroutines may send to the same channel.
402For example, let us have a channel of strings, and a suspending function that
403repeatedly sends a specified string to this channel with a specified delay:
404
405<!--- INCLUDE
406import kotlin.coroutines.experimental.*
407-->
408
Alexander Prendotacbeef102018-09-27 18:42:04 +0300409<div class="sample" markdown="1" theme="idea" data-highlight-only>
410
hadihariri7db55532018-09-15 10:35:08 +0200411```kotlin
412suspend fun sendString(channel: SendChannel<String>, s: String, time: Long) {
413 while (true) {
414 delay(time)
415 channel.send(s)
416 }
417}
418```
419
Alexander Prendotacbeef102018-09-27 18:42:04 +0300420</div>
421
hadihariri7db55532018-09-15 10:35:08 +0200422Now, let us see what happens if we launch a couple of coroutines sending strings
423(in this example we launch them in the context of the main thread as main coroutine's children):
424
Alexander Prendotacbeef102018-09-27 18:42:04 +0300425<div class="sample" markdown="1" theme="idea" data-highlight-only>
426
hadihariri7db55532018-09-15 10:35:08 +0200427```kotlin
Vsevolod Tolstopyatova2d80882018-09-24 19:51:49 +0300428fun main(args: Array<String>) = runBlocking {
hadihariri7db55532018-09-15 10:35:08 +0200429 val channel = Channel<String>()
430 launch { sendString(channel, "foo", 200L) }
431 launch { sendString(channel, "BAR!", 500L) }
432 repeat(6) { // receive first six
433 println(channel.receive())
434 }
435 coroutineContext.cancelChildren() // cancel all children to let main finish
436}
437```
438
Alexander Prendotacbeef102018-09-27 18:42:04 +0300439</div>
440
hadihariri7db55532018-09-15 10:35:08 +0200441> You can get full code [here](../core/kotlinx-coroutines-core/test/guide/example-channel-07.kt)
442
443The output is:
444
445```text
446foo
447foo
448BAR!
449foo
450foo
451BAR!
452```
453
454<!--- TEST -->
455
456### Buffered channels
457
458The channels shown so far had no buffer. Unbuffered channels transfer elements when sender and receiver
459meet each other (aka rendezvous). If send is invoked first, then it is suspended until receive is invoked,
460if receive is invoked first, it is suspended until send is invoked.
461
462Both [Channel()] factory function and [produce] builder take an optional `capacity` parameter to
463specify _buffer size_. Buffer allows senders to send multiple elements before suspending,
464similar to the `BlockingQueue` with a specified capacity, which blocks when buffer is full.
465
466Take a look at the behavior of the following code:
467
468<!--- INCLUDE
469import kotlin.coroutines.experimental.*
470-->
471
Alexander Prendotacbeef102018-09-27 18:42:04 +0300472<div class="sample" markdown="1" theme="idea" data-highlight-only>
473
hadihariri7db55532018-09-15 10:35:08 +0200474```kotlin
475fun main(args: Array<String>) = runBlocking<Unit> {
476 val channel = Channel<Int>(4) // create buffered channel
477 val sender = launch { // launch sender coroutine
478 repeat(10) {
479 println("Sending $it") // print before sending each element
480 channel.send(it) // will suspend when buffer is full
481 }
482 }
483 // don't receive anything... just wait....
484 delay(1000)
485 sender.cancel() // cancel sender coroutine
486}
487```
488
Alexander Prendotacbeef102018-09-27 18:42:04 +0300489</div>
490
hadihariri7db55532018-09-15 10:35:08 +0200491> You can get full code [here](../core/kotlinx-coroutines-core/test/guide/example-channel-08.kt)
492
493It prints "sending" _five_ times using a buffered channel with capacity of _four_:
494
495```text
496Sending 0
497Sending 1
498Sending 2
499Sending 3
500Sending 4
501```
502
503<!--- TEST -->
504
505The first four elements are added to the buffer and the sender suspends when trying to send the fifth one.
506
507### Channels are fair
508
509Send and receive operations to channels are _fair_ with respect to the order of their invocation from
510multiple coroutines. They are served in first-in first-out order, e.g. the first coroutine to invoke `receive`
511gets the element. In the following example two coroutines "ping" and "pong" are
512receiving the "ball" object from the shared "table" channel.
513
514<!--- INCLUDE
515import kotlin.coroutines.experimental.*
516-->
517
Alexander Prendotacbeef102018-09-27 18:42:04 +0300518<div class="sample" markdown="1" theme="idea" data-highlight-only>
519
hadihariri7db55532018-09-15 10:35:08 +0200520```kotlin
521data class Ball(var hits: Int)
522
Vsevolod Tolstopyatova2d80882018-09-24 19:51:49 +0300523fun main(args: Array<String>) = runBlocking {
hadihariri7db55532018-09-15 10:35:08 +0200524 val table = Channel<Ball>() // a shared table
525 launch { player("ping", table) }
526 launch { player("pong", table) }
527 table.send(Ball(0)) // serve the ball
528 delay(1000) // delay 1 second
529 coroutineContext.cancelChildren() // game over, cancel them
530}
531
532suspend fun player(name: String, table: Channel<Ball>) {
533 for (ball in table) { // receive the ball in a loop
534 ball.hits++
535 println("$name $ball")
536 delay(300) // wait a bit
537 table.send(ball) // send the ball back
538 }
539}
540```
541
Alexander Prendotacbeef102018-09-27 18:42:04 +0300542</div>
543
hadihariri7db55532018-09-15 10:35:08 +0200544> You can get full code [here](../core/kotlinx-coroutines-core/test/guide/example-channel-09.kt)
545
546The "ping" coroutine is started first, so it is the first one to receive the ball. Even though "ping"
547coroutine immediately starts receiving the ball again after sending it back to the table, the ball gets
548received by the "pong" coroutine, because it was already waiting for it:
549
550```text
551ping Ball(hits=1)
552pong Ball(hits=2)
553ping Ball(hits=3)
554pong Ball(hits=4)
555```
556
557<!--- TEST -->
558
559Note, that sometimes channels may produce executions that look unfair due to the nature of the executor
560that is being used. See [this issue](https://github.com/Kotlin/kotlinx.coroutines/issues/111) for details.
561
562### Ticker channels
563
564Ticker channel is a special rendezvous channel that produces `Unit` every time given delay passes since last consumption from this channel.
565Though it may seem to be useless standalone, it is a useful building block to create complex time-based [produce]
566pipelines and operators that do windowing and other time-dependent processing.
567Ticker channel can be used in [select] to perform "on tick" action.
568
569To create such channel use a factory method [ticker].
570To indicate that no further elements are needed use [ReceiveChannel.cancel] method on it.
571
572Now let's see how it works in practice:
573
Alexander Prendotacbeef102018-09-27 18:42:04 +0300574<div class="sample" markdown="1" theme="idea" data-highlight-only>
575
hadihariri7db55532018-09-15 10:35:08 +0200576```kotlin
577fun main(args: Array<String>) = runBlocking<Unit> {
Vsevolod Tolstopyatova2d80882018-09-24 19:51:49 +0300578 val tickerChannel = ticker(delayMillis = 100, initialDelayMillis = 0) // create ticker channel
hadihariri7db55532018-09-15 10:35:08 +0200579 var nextElement = withTimeoutOrNull(1) { tickerChannel.receive() }
580 println("Initial element is available immediately: $nextElement") // initial delay hasn't passed yet
581
582 nextElement = withTimeoutOrNull(50) { tickerChannel.receive() } // all subsequent elements has 100ms delay
583 println("Next element is not ready in 50 ms: $nextElement")
584
585 nextElement = withTimeoutOrNull(60) { tickerChannel.receive() }
586 println("Next element is ready in 100 ms: $nextElement")
587
588 // Emulate large consumption delays
589 println("Consumer pauses for 150ms")
590 delay(150)
591 // Next element is available immediately
592 nextElement = withTimeoutOrNull(1) { tickerChannel.receive() }
593 println("Next element is available immediately after large consumer delay: $nextElement")
594 // Note that the pause between `receive` calls is taken into account and next element arrives faster
595 nextElement = withTimeoutOrNull(60) { tickerChannel.receive() }
596 println("Next element is ready in 50ms after consumer pause in 150ms: $nextElement")
597
598 tickerChannel.cancel() // indicate that no more elements are needed
599}
600```
601
Alexander Prendotacbeef102018-09-27 18:42:04 +0300602</div>
603
hadihariri7db55532018-09-15 10:35:08 +0200604> You can get full code [here](../core/kotlinx-coroutines-core/test/guide/example-channel-10.kt)
605
606It prints following lines:
607
608```text
609Initial element is available immediately: kotlin.Unit
610Next element is not ready in 50 ms: null
611Next element is ready in 100 ms: kotlin.Unit
612Consumer pauses for 150ms
613Next element is available immediately after large consumer delay: kotlin.Unit
614Next element is ready in 50ms after consumer pause in 150ms: kotlin.Unit
615```
616
617<!--- TEST -->
618
619Note that [ticker] is aware of possible consumer pauses and, by default, adjusts next produced element
620delay if a pause occurs, trying to maintain a fixed rate of produced elements.
621
622Optionally, a `mode` parameter equal to [TickerMode.FIXED_DELAY] can be specified to maintain a fixed
623delay between elements.
624
625
626<!--- MODULE kotlinx-coroutines-core -->
Roman Elizarov99c28aa2018-09-23 18:42:36 +0300627<!--- INDEX kotlinx.coroutines.experimental -->
628[CoroutineScope]: https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines.experimental/-coroutine-scope/index.html
629[runBlocking]: https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines.experimental/run-blocking.html
630[kotlin.coroutines.experimental.CoroutineContext.cancelChildren]: https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines.experimental/kotlin.coroutines.experimental.-coroutine-context/cancel-children.html
631[Dispatchers.Default]: https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines.experimental/-dispatchers/-default.html
hadihariri7db55532018-09-15 10:35:08 +0200632<!--- INDEX kotlinx.coroutines.experimental.channels -->
633[Channel]: https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines.experimental.channels/-channel/index.html
634[SendChannel.send]: https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines.experimental.channels/-send-channel/send.html
635[ReceiveChannel.receive]: https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines.experimental.channels/-receive-channel/receive.html
636[SendChannel.close]: https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines.experimental.channels/-send-channel/close.html
637[produce]: https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines.experimental.channels/produce.html
638[consumeEach]: https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines.experimental.channels/consume-each.html
639[Channel()]: https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines.experimental.channels/-channel.html
640[ticker]: https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines.experimental.channels/ticker.html
641[ReceiveChannel.cancel]: https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines.experimental.channels/-receive-channel/cancel.html
642[TickerMode.FIXED_DELAY]: https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines.experimental.channels/-ticker-mode/-f-i-x-e-d_-d-e-l-a-y.html
Roman Elizarov99c28aa2018-09-23 18:42:36 +0300643<!--- INDEX kotlinx.coroutines.experimental.selects -->
644[select]: https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines.experimental.selects/select.html
hadihariri7db55532018-09-15 10:35:08 +0200645<!--- END -->