blob: 1d59b698067c3b33cdaff043064ea40126d2e075 [file] [log] [blame] [view]
Roman Elizarov43e90112017-05-10 11:25:20 +03001<!--- INCLUDE .*/example-([a-z]+)-([0-9a-z]+)\.kt
Roman Elizarova5e653f2017-02-13 13:49:55 +03002/*
Roman Elizarov1f74a2d2018-06-29 19:19:45 +03003 * Copyright 2016-2018 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
Roman Elizarova5e653f2017-02-13 13:49:55 +03004 */
Roman Elizarovf16fd272017-02-07 11:26:00 +03005
Roman Elizarova5e653f2017-02-13 13:49:55 +03006// This file was automatically generated from coroutines-guide.md by Knit tool. Do not edit.
Roman Elizarova9687a32018-06-29 17:28:38 +03007package kotlinx.coroutines.experimental.guide.$$1$$2
Roman Elizarovf16fd272017-02-07 11:26:00 +03008
Roman Elizarova5e653f2017-02-13 13:49:55 +03009import kotlinx.coroutines.experimental.*
Roman Elizarovf16fd272017-02-07 11:26:00 +030010-->
Vsevolod Tolstopyatovc1eb19f2018-06-19 17:04:09 +030011<!--- KNIT core/kotlinx-coroutines-core/test/guide/.*\.kt -->
12<!--- TEST_OUT core/kotlinx-coroutines-core/test/guide/test/GuideTest.kt
Roman Elizarov731f0ad2017-02-22 20:48:45 +030013// This file was automatically generated from coroutines-guide.md by Knit tool. Do not edit.
Roman Elizarova9687a32018-06-29 17:28:38 +030014package kotlinx.coroutines.experimental.guide.test
Roman Elizarov731f0ad2017-02-22 20:48:45 +030015
16import org.junit.Test
17
18class GuideTest {
19-->
Roman Elizarovf16fd272017-02-07 11:26:00 +030020
Roman Elizarov7deefb82017-01-31 10:33:17 +030021# Guide to kotlinx.coroutines by example
22
Roman Elizarova4d45d22017-11-20 16:47:09 +030023This is a guide on core features of `kotlinx.coroutines` with a series of examples.
Roman Elizarov7deefb82017-01-31 10:33:17 +030024
Roman Elizarov2a638922017-03-04 10:22:43 +030025## Introduction and setup
26
27Kotlin, as a language, provides only minimal low-level APIs in its standard library to enable various other
28libraries to utilize coroutines. Unlike many other languages with similar capabilities, `async` and `await`
29are not keywords in Kotlin and are not even part of its standard library.
30
Robert Hencke497d3432017-04-11 00:14:29 -040031`kotlinx.coroutines` is one such rich library. It contains a number of high-level
Roman Elizarova4d45d22017-11-20 16:47:09 +030032coroutine-enabled primitives that this guide covers, including `launch`, `async` and others.
Roman Elizarov2a638922017-03-04 10:22:43 +030033You need to add a dependency on `kotlinx-coroutines-core` module as explained
34[here](README.md#using-in-your-projects) to use primitives from this guide in your projects.
35
Roman Elizarov1293ccd2017-02-01 18:49:54 +030036## Table of contents
37
Roman Elizarovfa7723e2017-02-06 11:17:51 +030038<!--- TOC -->
39
Roman Elizarov1293ccd2017-02-01 18:49:54 +030040* [Coroutine basics](#coroutine-basics)
41 * [Your first coroutine](#your-first-coroutine)
42 * [Bridging blocking and non-blocking worlds](#bridging-blocking-and-non-blocking-worlds)
43 * [Waiting for a job](#waiting-for-a-job)
44 * [Extract function refactoring](#extract-function-refactoring)
45 * [Coroutines ARE light-weight](#coroutines-are-light-weight)
46 * [Coroutines are like daemon threads](#coroutines-are-like-daemon-threads)
47* [Cancellation and timeouts](#cancellation-and-timeouts)
48 * [Cancelling coroutine execution](#cancelling-coroutine-execution)
49 * [Cancellation is cooperative](#cancellation-is-cooperative)
50 * [Making computation code cancellable](#making-computation-code-cancellable)
51 * [Closing resources with finally](#closing-resources-with-finally)
52 * [Run non-cancellable block](#run-non-cancellable-block)
53 * [Timeout](#timeout)
54* [Composing suspending functions](#composing-suspending-functions)
55 * [Sequential by default](#sequential-by-default)
Roman Elizarov32d95322017-02-09 15:57:31 +030056 * [Concurrent using async](#concurrent-using-async)
57 * [Lazily started async](#lazily-started-async)
58 * [Async-style functions](#async-style-functions)
Roman Elizarov2f6d7c92017-02-03 15:16:07 +030059* [Coroutine context and dispatchers](#coroutine-context-and-dispatchers)
Roman Elizarovfa7723e2017-02-06 11:17:51 +030060 * [Dispatchers and threads](#dispatchers-and-threads)
Roman Elizarov2f6d7c92017-02-03 15:16:07 +030061 * [Unconfined vs confined dispatcher](#unconfined-vs-confined-dispatcher)
62 * [Debugging coroutines and threads](#debugging-coroutines-and-threads)
63 * [Jumping between threads](#jumping-between-threads)
64 * [Job in the context](#job-in-the-context)
65 * [Children of a coroutine](#children-of-a-coroutine)
66 * [Combining contexts](#combining-contexts)
Roman Elizarov8b38fa22017-09-27 17:44:31 +030067 * [Parental responsibilities](#parental-responsibilities)
Roman Elizarov2f6d7c92017-02-03 15:16:07 +030068 * [Naming coroutines for debugging](#naming-coroutines-for-debugging)
Roman Elizarov2fd7cb32017-02-11 23:18:59 +030069 * [Cancellation via explicit job](#cancellation-via-explicit-job)
Vsevolod Tolstopyatov590696d2018-08-08 15:22:33 +030070* [Exception handling](#exception-handling)
71 * [Exception propagation](#exception-propagation)
72 * [CoroutineExceptionHandler](#coroutineexceptionhandler)
73 * [Cancellation and exceptions](#cancellation-and-exceptions)
74 * [Exceptions aggregation](#exceptions-aggregation)
Roman Elizarovb7721cf2017-02-03 19:23:08 +030075* [Channels](#channels)
76 * [Channel basics](#channel-basics)
77 * [Closing and iteration over channels](#closing-and-iteration-over-channels)
78 * [Building channel producers](#building-channel-producers)
79 * [Pipelines](#pipelines)
80 * [Prime numbers with pipeline](#prime-numbers-with-pipeline)
81 * [Fan-out](#fan-out)
82 * [Fan-in](#fan-in)
83 * [Buffered channels](#buffered-channels)
Vsevolod Tolstopyatov03d2ff72018-05-29 17:28:20 +030084 * [Ticker channels](#ticker-channels)
Roman Elizarovb0517ba2017-02-27 14:03:14 +030085 * [Channels are fair](#channels-are-fair)
Roman Elizarovf5bc0472017-02-22 11:38:13 +030086* [Shared mutable state and concurrency](#shared-mutable-state-and-concurrency)
87 * [The problem](#the-problem)
Roman Elizarov1e459602017-02-27 11:05:17 +030088 * [Volatiles are of no help](#volatiles-are-of-no-help)
Roman Elizarovf5bc0472017-02-22 11:38:13 +030089 * [Thread-safe data structures](#thread-safe-data-structures)
Roman Elizarov1e459602017-02-27 11:05:17 +030090 * [Thread confinement fine-grained](#thread-confinement-fine-grained)
91 * [Thread confinement coarse-grained](#thread-confinement-coarse-grained)
Roman Elizarovf5bc0472017-02-22 11:38:13 +030092 * [Mutual exclusion](#mutual-exclusion)
93 * [Actors](#actors)
Roman Elizarovd4dcbe22017-02-22 09:57:46 +030094* [Select expression](#select-expression)
95 * [Selecting from channels](#selecting-from-channels)
96 * [Selecting on close](#selecting-on-close)
97 * [Selecting to send](#selecting-to-send)
98 * [Selecting deferred values](#selecting-deferred-values)
99 * [Switch over a channel of deferred values](#switch-over-a-channel-of-deferred-values)
Roman Elizarov8db17332017-03-09 12:40:45 +0300100* [Further reading](#further-reading)
Roman Elizarovfa7723e2017-02-06 11:17:51 +0300101
Roman Elizarova5e653f2017-02-13 13:49:55 +0300102<!--- END_TOC -->
Roman Elizarov1293ccd2017-02-01 18:49:54 +0300103
104## Coroutine basics
105
106This section covers basic coroutine concepts.
107
108### Your first coroutine
Roman Elizarov7deefb82017-01-31 10:33:17 +0300109
110Run the following code:
111
112```kotlin
113fun main(args: Array<String>) {
Roman Elizarova4d45d22017-11-20 16:47:09 +0300114 launch { // launch new coroutine in background and continue
Roman Elizarov7deefb82017-01-31 10:33:17 +0300115 delay(1000L) // non-blocking delay for 1 second (default time unit is ms)
116 println("World!") // print after delay
117 }
Roman Elizarova4d45d22017-11-20 16:47:09 +0300118 println("Hello,") // main thread continues while coroutine is delayed
Roman Elizarov7deefb82017-01-31 10:33:17 +0300119 Thread.sleep(2000L) // block main thread for 2 seconds to keep JVM alive
120}
121```
122
Vsevolod Tolstopyatovc1eb19f2018-06-19 17:04:09 +0300123> You can get full code [here](core/kotlinx-coroutines-core/test/guide/example-basic-01.kt)
Roman Elizarov7deefb82017-01-31 10:33:17 +0300124
125Run this code:
126
Roman Elizarov731f0ad2017-02-22 20:48:45 +0300127```text
Roman Elizarov7deefb82017-01-31 10:33:17 +0300128Hello,
129World!
130```
131
Roman Elizarov731f0ad2017-02-22 20:48:45 +0300132<!--- TEST -->
133
Roman Elizarov419a6c82017-02-09 18:36:22 +0300134Essentially, coroutines are light-weight threads.
135They are launched with [launch] _coroutine builder_.
136You can achieve the same result replacing
Roman Elizarov66f018c2017-09-29 21:39:03 +0300137`launch { ... }` with `thread { ... }` and `delay(...)` with `Thread.sleep(...)`. Try it.
Roman Elizarov7deefb82017-01-31 10:33:17 +0300138
Roman Elizarov66f018c2017-09-29 21:39:03 +0300139If you start by replacing `launch` by `thread`, the compiler produces the following error:
Roman Elizarov7deefb82017-01-31 10:33:17 +0300140
141```
142Error: Kotlin: Suspend functions are only allowed to be called from a coroutine or another suspend function
143```
144
Roman Elizarov419a6c82017-02-09 18:36:22 +0300145That is because [delay] is a special _suspending function_ that does not block a thread, but _suspends_
Roman Elizarov7deefb82017-01-31 10:33:17 +0300146coroutine and it can be only used from a coroutine.
147
Roman Elizarov1293ccd2017-02-01 18:49:54 +0300148### Bridging blocking and non-blocking worlds
Roman Elizarov7deefb82017-01-31 10:33:17 +0300149
Roman Elizarova4d45d22017-11-20 16:47:09 +0300150The first example mixes _non-blocking_ `delay(...)` and _blocking_ `Thread.sleep(...)` in the same code.
151It is easy to get lost which one is blocking and which one is not.
152Let's be explicit about blocking using [runBlocking] coroutine builder:
Roman Elizarov7deefb82017-01-31 10:33:17 +0300153
154```kotlin
Roman Elizarova4d45d22017-11-20 16:47:09 +0300155fun main(args: Array<String>) {
156 launch { // launch new coroutine in background and continue
Roman Elizarov7deefb82017-01-31 10:33:17 +0300157 delay(1000L)
158 println("World!")
159 }
Roman Elizarova4d45d22017-11-20 16:47:09 +0300160 println("Hello,") // main thread continues here immediately
161 runBlocking { // but this expression blocks the main thread
162 delay(2000L) // ... while we delay for 2 seconds to keep JVM alive
163 }
Roman Elizarov7deefb82017-01-31 10:33:17 +0300164}
165```
166
Vsevolod Tolstopyatovc1eb19f2018-06-19 17:04:09 +0300167> You can get full code [here](core/kotlinx-coroutines-core/test/guide/example-basic-02.kt)
Roman Elizarov7deefb82017-01-31 10:33:17 +0300168
Roman Elizarov731f0ad2017-02-22 20:48:45 +0300169<!--- TEST
170Hello,
171World!
172-->
173
Roman Elizarov419a6c82017-02-09 18:36:22 +0300174The result is the same, but this code uses only non-blocking [delay].
Tylos81451de2017-12-17 21:33:17 +0100175The main thread, that invokes `runBlocking`, _blocks_ until the coroutine inside `runBlocking` completes.
Roman Elizarov7deefb82017-01-31 10:33:17 +0300176
Roman Elizarova4d45d22017-11-20 16:47:09 +0300177This example can be also rewritten in a more idiomatic way, using `runBlocking` to wrap
178the execution of the main function:
179
180```kotlin
181fun main(args: Array<String>) = runBlocking<Unit> { // start main coroutine
182 launch { // launch new coroutine in background and continue
183 delay(1000L)
184 println("World!")
185 }
186 println("Hello,") // main coroutine continues here immediately
187 delay(2000L) // delaying for 2 seconds to keep JVM alive
188}
189```
190
Vsevolod Tolstopyatovc1eb19f2018-06-19 17:04:09 +0300191> You can get full code [here](core/kotlinx-coroutines-core/test/guide/example-basic-02b.kt)
Roman Elizarova4d45d22017-11-20 16:47:09 +0300192
193<!--- TEST
194Hello,
195World!
196-->
197
198Here `runBlocking<Unit> { ... }` works as an adaptor that is used to start the top-level main coroutine.
199We explicitly specify its `Unit` return type, because a well-formed `main` function in Kotlin has to return `Unit`.
Roman Elizarov7deefb82017-01-31 10:33:17 +0300200
201This is also a way to write unit-tests for suspending functions:
202
203```kotlin
204class MyTest {
205 @Test
206 fun testMySuspendingFunction() = runBlocking<Unit> {
207 // here we can use suspending functions using any assertion style that we like
208 }
209}
210```
Roman Elizarovb3d55a52017-02-03 12:47:21 +0300211
212<!--- CLEAR -->
Roman Elizarov7deefb82017-01-31 10:33:17 +0300213
Roman Elizarov1293ccd2017-02-01 18:49:54 +0300214### Waiting for a job
Roman Elizarov7deefb82017-01-31 10:33:17 +0300215
Roman Elizarov1293ccd2017-02-01 18:49:54 +0300216Delaying for a time while another coroutine is working is not a good approach. Let's explicitly
Roman Elizarov419a6c82017-02-09 18:36:22 +0300217wait (in a non-blocking way) until the background [Job] that we have launched is complete:
Roman Elizarov7deefb82017-01-31 10:33:17 +0300218
219```kotlin
220fun main(args: Array<String>) = runBlocking<Unit> {
Roman Elizarov66f018c2017-09-29 21:39:03 +0300221 val job = launch { // launch new coroutine and keep a reference to its Job
Roman Elizarov7deefb82017-01-31 10:33:17 +0300222 delay(1000L)
223 println("World!")
224 }
225 println("Hello,")
226 job.join() // wait until child coroutine completes
227}
228```
229
Vsevolod Tolstopyatovc1eb19f2018-06-19 17:04:09 +0300230> You can get full code [here](core/kotlinx-coroutines-core/test/guide/example-basic-03.kt)
Roman Elizarov7deefb82017-01-31 10:33:17 +0300231
Roman Elizarov731f0ad2017-02-22 20:48:45 +0300232<!--- TEST
233Hello,
234World!
235-->
236
Roman Elizarov7deefb82017-01-31 10:33:17 +0300237Now the result is still the same, but the code of the main coroutine is not tied to the duration of
Roman Elizarov1293ccd2017-02-01 18:49:54 +0300238the background job in any way. Much better.
Roman Elizarov7deefb82017-01-31 10:33:17 +0300239
Roman Elizarov1293ccd2017-02-01 18:49:54 +0300240### Extract function refactoring
Roman Elizarov7deefb82017-01-31 10:33:17 +0300241
Roman Elizarov66f018c2017-09-29 21:39:03 +0300242Let's extract the block of code inside `launch { ... }` into a separate function. When you
Roman Elizarov7deefb82017-01-31 10:33:17 +0300243perform "Extract function" refactoring on this code you get a new function with `suspend` modifier.
244That is your first _suspending function_. Suspending functions can be used inside coroutines
245just like regular functions, but their additional feature is that they can, in turn,
246use other suspending functions, like `delay` in this example, to _suspend_ execution of a coroutine.
247
248```kotlin
249fun main(args: Array<String>) = runBlocking<Unit> {
Roman Elizarov66f018c2017-09-29 21:39:03 +0300250 val job = launch { doWorld() }
Roman Elizarov7deefb82017-01-31 10:33:17 +0300251 println("Hello,")
252 job.join()
253}
254
255// this is your first suspending function
256suspend fun doWorld() {
257 delay(1000L)
258 println("World!")
259}
260```
261
Vsevolod Tolstopyatovc1eb19f2018-06-19 17:04:09 +0300262> You can get full code [here](core/kotlinx-coroutines-core/test/guide/example-basic-04.kt)
Roman Elizarov7deefb82017-01-31 10:33:17 +0300263
Roman Elizarov731f0ad2017-02-22 20:48:45 +0300264<!--- TEST
265Hello,
266World!
267-->
268
Roman Elizarov1293ccd2017-02-01 18:49:54 +0300269### Coroutines ARE light-weight
Roman Elizarov7deefb82017-01-31 10:33:17 +0300270
271Run the following code:
272
273```kotlin
274fun main(args: Array<String>) = runBlocking<Unit> {
Roman Elizarov66f018c2017-09-29 21:39:03 +0300275 val jobs = List(100_000) { // launch a lot of coroutines and list their jobs
276 launch {
Roman Elizarov7deefb82017-01-31 10:33:17 +0300277 delay(1000L)
278 print(".")
279 }
280 }
281 jobs.forEach { it.join() } // wait for all jobs to complete
282}
283```
284
Vsevolod Tolstopyatovc1eb19f2018-06-19 17:04:09 +0300285> You can get full code [here](core/kotlinx-coroutines-core/test/guide/example-basic-05.kt)
Roman Elizarov7deefb82017-01-31 10:33:17 +0300286
Roman Elizarov731f0ad2017-02-22 20:48:45 +0300287<!--- TEST lines.size == 1 && lines[0] == ".".repeat(100_000) -->
288
Roman Elizarov66f018c2017-09-29 21:39:03 +0300289It launches 100K coroutines and, after a second, each coroutine prints a dot.
Roman Elizarov7deefb82017-01-31 10:33:17 +0300290Now, try that with threads. What would happen? (Most likely your code will produce some sort of out-of-memory error)
291
Roman Elizarov1293ccd2017-02-01 18:49:54 +0300292### Coroutines are like daemon threads
Roman Elizarov7deefb82017-01-31 10:33:17 +0300293
294The following code launches a long-running coroutine that prints "I'm sleeping" twice a second and then
Roman Elizarov1293ccd2017-02-01 18:49:54 +0300295returns from the main function after some delay:
Roman Elizarov7deefb82017-01-31 10:33:17 +0300296
297```kotlin
298fun main(args: Array<String>) = runBlocking<Unit> {
Roman Elizarov66f018c2017-09-29 21:39:03 +0300299 launch {
Roman Elizarov7deefb82017-01-31 10:33:17 +0300300 repeat(1000) { i ->
301 println("I'm sleeping $i ...")
302 delay(500L)
303 }
304 }
305 delay(1300L) // just quit after delay
306}
307```
308
Vsevolod Tolstopyatovc1eb19f2018-06-19 17:04:09 +0300309> You can get full code [here](core/kotlinx-coroutines-core/test/guide/example-basic-06.kt)
Roman Elizarov7deefb82017-01-31 10:33:17 +0300310
311You can run and see that it prints three lines and terminates:
312
Roman Elizarov731f0ad2017-02-22 20:48:45 +0300313```text
Roman Elizarov7deefb82017-01-31 10:33:17 +0300314I'm sleeping 0 ...
315I'm sleeping 1 ...
316I'm sleeping 2 ...
317```
318
Roman Elizarov731f0ad2017-02-22 20:48:45 +0300319<!--- TEST -->
320
Roman Elizarov7deefb82017-01-31 10:33:17 +0300321Active coroutines do not keep the process alive. They are like daemon threads.
322
Roman Elizarov1293ccd2017-02-01 18:49:54 +0300323## Cancellation and timeouts
324
325This section covers coroutine cancellation and timeouts.
326
327### Cancelling coroutine execution
Roman Elizarov7deefb82017-01-31 10:33:17 +0300328
Brad977ada12018-07-19 16:01:40 -0400329In a small application the return from "main" method might sound like a good idea to get all coroutines
330implicitly terminated but in a larger, long-running application, you need finer-grained control.
Roman Elizarov419a6c82017-02-09 18:36:22 +0300331The [launch] function returns a [Job] that can be used to cancel running coroutine:
Roman Elizarov7deefb82017-01-31 10:33:17 +0300332
333```kotlin
334fun main(args: Array<String>) = runBlocking<Unit> {
Roman Elizarov66f018c2017-09-29 21:39:03 +0300335 val job = launch {
Roman Elizarov7deefb82017-01-31 10:33:17 +0300336 repeat(1000) { i ->
337 println("I'm sleeping $i ...")
338 delay(500L)
339 }
340 }
341 delay(1300L) // delay a bit
Roman Elizarov1293ccd2017-02-01 18:49:54 +0300342 println("main: I'm tired of waiting!")
Roman Elizarov7deefb82017-01-31 10:33:17 +0300343 job.cancel() // cancels the job
Roman Elizarov8b38fa22017-09-27 17:44:31 +0300344 job.join() // waits for job's completion
Roman Elizarov1293ccd2017-02-01 18:49:54 +0300345 println("main: Now I can quit.")
Roman Elizarov7deefb82017-01-31 10:33:17 +0300346}
347```
348
Vsevolod Tolstopyatovc1eb19f2018-06-19 17:04:09 +0300349> You can get full code [here](core/kotlinx-coroutines-core/test/guide/example-cancel-01.kt)
Roman Elizarov7deefb82017-01-31 10:33:17 +0300350
Roman Elizarov1293ccd2017-02-01 18:49:54 +0300351It produces the following output:
352
Roman Elizarov731f0ad2017-02-22 20:48:45 +0300353```text
Roman Elizarov1293ccd2017-02-01 18:49:54 +0300354I'm sleeping 0 ...
355I'm sleeping 1 ...
356I'm sleeping 2 ...
357main: I'm tired of waiting!
358main: Now I can quit.
359```
360
Roman Elizarov731f0ad2017-02-22 20:48:45 +0300361<!--- TEST -->
362
Roman Elizarov1293ccd2017-02-01 18:49:54 +0300363As soon as main invokes `job.cancel`, we don't see any output from the other coroutine because it was cancelled.
Roman Elizarov88396732017-09-27 21:30:47 +0300364There is also a [Job] extension function [cancelAndJoin]
365that combines [cancel][Job.cancel] and [join][Job.join] invocations.
Roman Elizarov1293ccd2017-02-01 18:49:54 +0300366
367### Cancellation is cooperative
Roman Elizarov7deefb82017-01-31 10:33:17 +0300368
Tair Rzayevaf734622017-02-01 22:30:16 +0200369Coroutine cancellation is _cooperative_. A coroutine code has to cooperate to be cancellable.
Roman Elizarov7deefb82017-01-31 10:33:17 +0300370All the suspending functions in `kotlinx.coroutines` are _cancellable_. They check for cancellation of
Roman Elizarov419a6c82017-02-09 18:36:22 +0300371coroutine and throw [CancellationException] when cancelled. However, if a coroutine is working in
Roman Elizarov7deefb82017-01-31 10:33:17 +0300372a computation and does not check for cancellation, then it cannot be cancelled, like the following
373example shows:
374
375```kotlin
376fun main(args: Array<String>) = runBlocking<Unit> {
Roman Elizarov24cd6542017-08-03 21:20:04 -0700377 val startTime = System.currentTimeMillis()
Roman Elizarov66f018c2017-09-29 21:39:03 +0300378 val job = launch {
Roman Elizarov24cd6542017-08-03 21:20:04 -0700379 var nextPrintTime = startTime
Roman Elizarov7deefb82017-01-31 10:33:17 +0300380 var i = 0
Roman Elizarov8b38fa22017-09-27 17:44:31 +0300381 while (i < 5) { // computation loop, just wastes CPU
Roman Elizarov24cd6542017-08-03 21:20:04 -0700382 // print a message twice a second
383 if (System.currentTimeMillis() >= nextPrintTime) {
Roman Elizarov7deefb82017-01-31 10:33:17 +0300384 println("I'm sleeping ${i++} ...")
Roman Elizarov35d2c342017-07-20 14:54:39 +0300385 nextPrintTime += 500L
Roman Elizarov7deefb82017-01-31 10:33:17 +0300386 }
387 }
388 }
389 delay(1300L) // delay a bit
Roman Elizarov1293ccd2017-02-01 18:49:54 +0300390 println("main: I'm tired of waiting!")
Roman Elizarov8b38fa22017-09-27 17:44:31 +0300391 job.cancelAndJoin() // cancels the job and waits for its completion
Roman Elizarov1293ccd2017-02-01 18:49:54 +0300392 println("main: Now I can quit.")
Roman Elizarov7deefb82017-01-31 10:33:17 +0300393}
394```
395
Vsevolod Tolstopyatovc1eb19f2018-06-19 17:04:09 +0300396> You can get full code [here](core/kotlinx-coroutines-core/test/guide/example-cancel-02.kt)
Roman Elizarov7deefb82017-01-31 10:33:17 +0300397
Roman Elizarov8b38fa22017-09-27 17:44:31 +0300398Run it to see that it continues to print "I'm sleeping" even after cancellation
399until the job completes by itself after five iterations.
Roman Elizarov7deefb82017-01-31 10:33:17 +0300400
Roman Elizarov731f0ad2017-02-22 20:48:45 +0300401<!--- TEST
402I'm sleeping 0 ...
403I'm sleeping 1 ...
404I'm sleeping 2 ...
405main: I'm tired of waiting!
406I'm sleeping 3 ...
407I'm sleeping 4 ...
Roman Elizarov731f0ad2017-02-22 20:48:45 +0300408main: Now I can quit.
409-->
410
Roman Elizarov1293ccd2017-02-01 18:49:54 +0300411### Making computation code cancellable
Roman Elizarov7deefb82017-01-31 10:33:17 +0300412
413There are two approaches to making computation code cancellable. The first one is to periodically
Roman Elizarov66f018c2017-09-29 21:39:03 +0300414invoke a suspending function that checks for cancellation. There is a [yield] function that is a good choice for that purpose.
Roman Elizarov1293ccd2017-02-01 18:49:54 +0300415The other one is to explicitly check the cancellation status. Let us try the later approach.
Roman Elizarov7deefb82017-01-31 10:33:17 +0300416
Roman Elizarov8b38fa22017-09-27 17:44:31 +0300417Replace `while (i < 5)` in the previous example with `while (isActive)` and rerun it.
Roman Elizarov7deefb82017-01-31 10:33:17 +0300418
Roman Elizarovb3d55a52017-02-03 12:47:21 +0300419```kotlin
420fun main(args: Array<String>) = runBlocking<Unit> {
Roman Elizarov24cd6542017-08-03 21:20:04 -0700421 val startTime = System.currentTimeMillis()
Roman Elizarov66f018c2017-09-29 21:39:03 +0300422 val job = launch {
Roman Elizarov24cd6542017-08-03 21:20:04 -0700423 var nextPrintTime = startTime
Roman Elizarovb3d55a52017-02-03 12:47:21 +0300424 var i = 0
425 while (isActive) { // cancellable computation loop
Roman Elizarov24cd6542017-08-03 21:20:04 -0700426 // print a message twice a second
427 if (System.currentTimeMillis() >= nextPrintTime) {
Roman Elizarovb3d55a52017-02-03 12:47:21 +0300428 println("I'm sleeping ${i++} ...")
Roman Elizarov24cd6542017-08-03 21:20:04 -0700429 nextPrintTime += 500L
Roman Elizarovb3d55a52017-02-03 12:47:21 +0300430 }
431 }
432 }
433 delay(1300L) // delay a bit
434 println("main: I'm tired of waiting!")
Roman Elizarov8b38fa22017-09-27 17:44:31 +0300435 job.cancelAndJoin() // cancels the job and waits for its completion
Roman Elizarovb3d55a52017-02-03 12:47:21 +0300436 println("main: Now I can quit.")
437}
438```
439
Vsevolod Tolstopyatovc1eb19f2018-06-19 17:04:09 +0300440> You can get full code [here](core/kotlinx-coroutines-core/test/guide/example-cancel-03.kt)
Roman Elizarov7deefb82017-01-31 10:33:17 +0300441
Roman Elizarov8b38fa22017-09-27 17:44:31 +0300442As you can see, now this loop is cancelled. [isActive][CoroutineScope.isActive] is a property that is available inside
Roman Elizarov419a6c82017-02-09 18:36:22 +0300443the code of coroutines via [CoroutineScope] object.
Roman Elizarov7deefb82017-01-31 10:33:17 +0300444
Roman Elizarov731f0ad2017-02-22 20:48:45 +0300445<!--- TEST
446I'm sleeping 0 ...
447I'm sleeping 1 ...
448I'm sleeping 2 ...
449main: I'm tired of waiting!
450main: Now I can quit.
451-->
452
Roman Elizarov1293ccd2017-02-01 18:49:54 +0300453### Closing resources with finally
454
Roman Elizarov419a6c82017-02-09 18:36:22 +0300455Cancellable suspending functions throw [CancellationException] on cancellation which can be handled in
Brad977ada12018-07-19 16:01:40 -0400456the usual way. For example, `try {...} finally {...}` expression and Kotlin `use` function execute their
Roman Elizarov1293ccd2017-02-01 18:49:54 +0300457finalization actions normally when coroutine is cancelled:
458
459```kotlin
460fun main(args: Array<String>) = runBlocking<Unit> {
Roman Elizarov66f018c2017-09-29 21:39:03 +0300461 val job = launch {
Roman Elizarov1293ccd2017-02-01 18:49:54 +0300462 try {
463 repeat(1000) { i ->
464 println("I'm sleeping $i ...")
465 delay(500L)
466 }
467 } finally {
468 println("I'm running finally")
469 }
470 }
471 delay(1300L) // delay a bit
472 println("main: I'm tired of waiting!")
Roman Elizarov8b38fa22017-09-27 17:44:31 +0300473 job.cancelAndJoin() // cancels the job and waits for its completion
Roman Elizarov1293ccd2017-02-01 18:49:54 +0300474 println("main: Now I can quit.")
475}
476```
477
Vsevolod Tolstopyatovc1eb19f2018-06-19 17:04:09 +0300478> You can get full code [here](core/kotlinx-coroutines-core/test/guide/example-cancel-04.kt)
Roman Elizarov1293ccd2017-02-01 18:49:54 +0300479
Roman Elizarov88396732017-09-27 21:30:47 +0300480Both [join][Job.join] and [cancelAndJoin] wait for all the finalization actions to complete,
481so the example above produces the following output:
Roman Elizarov1293ccd2017-02-01 18:49:54 +0300482
Roman Elizarov731f0ad2017-02-22 20:48:45 +0300483```text
Roman Elizarov1293ccd2017-02-01 18:49:54 +0300484I'm sleeping 0 ...
485I'm sleeping 1 ...
486I'm sleeping 2 ...
487main: I'm tired of waiting!
488I'm running finally
489main: Now I can quit.
490```
491
Roman Elizarov731f0ad2017-02-22 20:48:45 +0300492<!--- TEST -->
493
Roman Elizarov1293ccd2017-02-01 18:49:54 +0300494### Run non-cancellable block
495
496Any attempt to use a suspending function in the `finally` block of the previous example will cause
Roman Elizarov419a6c82017-02-09 18:36:22 +0300497[CancellationException], because the coroutine running this code is cancelled. Usually, this is not a
Roman Elizarov1293ccd2017-02-01 18:49:54 +0300498problem, since all well-behaving closing operations (closing a file, cancelling a job, or closing any kind of a
499communication channel) are usually non-blocking and do not involve any suspending functions. However, in the
500rare case when you need to suspend in the cancelled coroutine you can wrap the corresponding code in
Roman Elizarovf9e13f52017-12-21 12:23:15 +0300501`withContext(NonCancellable) {...}` using [withContext] function and [NonCancellable] context as the following example shows:
Roman Elizarov1293ccd2017-02-01 18:49:54 +0300502
503```kotlin
504fun main(args: Array<String>) = runBlocking<Unit> {
Roman Elizarov66f018c2017-09-29 21:39:03 +0300505 val job = launch {
Roman Elizarov1293ccd2017-02-01 18:49:54 +0300506 try {
507 repeat(1000) { i ->
508 println("I'm sleeping $i ...")
509 delay(500L)
510 }
511 } finally {
Roman Elizarovf9e13f52017-12-21 12:23:15 +0300512 withContext(NonCancellable) {
Roman Elizarov1293ccd2017-02-01 18:49:54 +0300513 println("I'm running finally")
514 delay(1000L)
515 println("And I've just delayed for 1 sec because I'm non-cancellable")
516 }
517 }
518 }
519 delay(1300L) // delay a bit
520 println("main: I'm tired of waiting!")
Roman Elizarov8b38fa22017-09-27 17:44:31 +0300521 job.cancelAndJoin() // cancels the job and waits for its completion
Roman Elizarov1293ccd2017-02-01 18:49:54 +0300522 println("main: Now I can quit.")
523}
524```
525
Vsevolod Tolstopyatovc1eb19f2018-06-19 17:04:09 +0300526> You can get full code [here](core/kotlinx-coroutines-core/test/guide/example-cancel-05.kt)
Roman Elizarov1293ccd2017-02-01 18:49:54 +0300527
Roman Elizarov731f0ad2017-02-22 20:48:45 +0300528<!--- TEST
529I'm sleeping 0 ...
530I'm sleeping 1 ...
531I'm sleeping 2 ...
532main: I'm tired of waiting!
533I'm running finally
534And I've just delayed for 1 sec because I'm non-cancellable
535main: Now I can quit.
536-->
537
Roman Elizarov1293ccd2017-02-01 18:49:54 +0300538### Timeout
539
Brad977ada12018-07-19 16:01:40 -0400540The most obvious reason to cancel coroutine execution in practice
Roman Elizarov1293ccd2017-02-01 18:49:54 +0300541is because its execution time has exceeded some timeout.
Roman Elizarov419a6c82017-02-09 18:36:22 +0300542While you can manually track the reference to the corresponding [Job] and launch a separate coroutine to cancel
543the tracked one after delay, there is a ready to use [withTimeout] function that does it.
Roman Elizarov1293ccd2017-02-01 18:49:54 +0300544Look at the following example:
545
546```kotlin
547fun main(args: Array<String>) = runBlocking<Unit> {
548 withTimeout(1300L) {
549 repeat(1000) { i ->
550 println("I'm sleeping $i ...")
551 delay(500L)
552 }
553 }
554}
555```
556
Vsevolod Tolstopyatovc1eb19f2018-06-19 17:04:09 +0300557> You can get full code [here](core/kotlinx-coroutines-core/test/guide/example-cancel-06.kt)
Roman Elizarov1293ccd2017-02-01 18:49:54 +0300558
559It produces the following output:
560
Roman Elizarov731f0ad2017-02-22 20:48:45 +0300561```text
Roman Elizarov1293ccd2017-02-01 18:49:54 +0300562I'm sleeping 0 ...
563I'm sleeping 1 ...
564I'm sleeping 2 ...
Roman Elizarov63f6ea22017-09-06 18:42:34 +0300565Exception in thread "main" kotlinx.coroutines.experimental.TimeoutCancellationException: Timed out waiting for 1300 MILLISECONDS
Roman Elizarov1293ccd2017-02-01 18:49:54 +0300566```
567
Roman Elizarov731f0ad2017-02-22 20:48:45 +0300568<!--- TEST STARTS_WITH -->
569
Roman Elizarov63f6ea22017-09-06 18:42:34 +0300570The `TimeoutCancellationException` that is thrown by [withTimeout] is a subclass of [CancellationException].
Roman Elizarovca9d5be2017-04-20 19:23:18 +0300571We have not seen its stack trace printed on the console before. That is because
Roman Elizarov7c864d82017-02-27 10:17:50 +0300572inside a cancelled coroutine `CancellationException` is considered to be a normal reason for coroutine completion.
Roman Elizarov1293ccd2017-02-01 18:49:54 +0300573However, in this example we have used `withTimeout` right inside the `main` function.
574
575Because cancellation is just an exception, all the resources will be closed in a usual way.
Roman Elizarov63f6ea22017-09-06 18:42:34 +0300576You can wrap the code with timeout in `try {...} catch (e: TimeoutCancellationException) {...}` block if
577you need to do some additional action specifically on any kind of timeout or use [withTimeoutOrNull] function
Roman Elizarov8b38fa22017-09-27 17:44:31 +0300578that is similar to [withTimeout], but returns `null` on timeout instead of throwing an exception:
579
580```kotlin
581fun main(args: Array<String>) = runBlocking<Unit> {
582 val result = withTimeoutOrNull(1300L) {
583 repeat(1000) { i ->
584 println("I'm sleeping $i ...")
585 delay(500L)
586 }
587 "Done" // will get cancelled before it produces this result
588 }
589 println("Result is $result")
590}
591```
592
Vsevolod Tolstopyatovc1eb19f2018-06-19 17:04:09 +0300593> You can get full code [here](core/kotlinx-coroutines-core/test/guide/example-cancel-07.kt)
Roman Elizarov8b38fa22017-09-27 17:44:31 +0300594
595There is no longer an exception when running this code:
596
597```text
598I'm sleeping 0 ...
599I'm sleeping 1 ...
600I'm sleeping 2 ...
601Result is null
602```
603
604<!--- TEST -->
Roman Elizarov1293ccd2017-02-01 18:49:54 +0300605
606## Composing suspending functions
607
608This section covers various approaches to composition of suspending functions.
609
610### Sequential by default
611
612Assume that we have two suspending functions defined elsewhere that do something useful like some kind of
Roman Elizarovb7721cf2017-02-03 19:23:08 +0300613remote service call or computation. We just pretend they are useful, but actually each one just
614delays for a second for the purpose of this example:
Roman Elizarov1293ccd2017-02-01 18:49:54 +0300615
Roman Elizarovfa7723e2017-02-06 11:17:51 +0300616<!--- INCLUDE .*/example-compose-([0-9]+).kt
Roman Elizarov9fe5f462018-02-21 19:05:52 +0300617import kotlin.system.*
Roman Elizarovfa7723e2017-02-06 11:17:51 +0300618-->
619
Roman Elizarov1293ccd2017-02-01 18:49:54 +0300620```kotlin
621suspend fun doSomethingUsefulOne(): Int {
622 delay(1000L) // pretend we are doing something useful here
623 return 13
624}
625
626suspend fun doSomethingUsefulTwo(): Int {
627 delay(1000L) // pretend we are doing something useful here, too
628 return 29
629}
630```
631
Roman Elizarovfa7723e2017-02-06 11:17:51 +0300632<!--- INCLUDE .*/example-compose-([0-9]+).kt -->
633
Roman Elizarov1293ccd2017-02-01 18:49:54 +0300634What do we do if need to invoke them _sequentially_ -- first `doSomethingUsefulOne` _and then_
635`doSomethingUsefulTwo` and compute the sum of their results?
Ronen Sabagd2d42ea2017-12-24 21:55:06 +0200636In practice we do this if we use the results of the first function to make a decision on whether we need
Roman Elizarov1293ccd2017-02-01 18:49:54 +0300637to invoke the second one or to decide on how to invoke it.
638
639We just use a normal sequential invocation, because the code in the coroutine, just like in the regular
Roman Elizarov32d95322017-02-09 15:57:31 +0300640code, is _sequential_ by default. The following example demonstrates it by measuring the total
Roman Elizarov1293ccd2017-02-01 18:49:54 +0300641time it takes to execute both suspending functions:
642
643```kotlin
644fun main(args: Array<String>) = runBlocking<Unit> {
645 val time = measureTimeMillis {
646 val one = doSomethingUsefulOne()
647 val two = doSomethingUsefulTwo()
648 println("The answer is ${one + two}")
649 }
650 println("Completed in $time ms")
651}
652```
653
Vsevolod Tolstopyatovc1eb19f2018-06-19 17:04:09 +0300654> You can get full code [here](core/kotlinx-coroutines-core/test/guide/example-compose-01.kt)
Roman Elizarov1293ccd2017-02-01 18:49:54 +0300655
656It produces something like this:
657
Roman Elizarov731f0ad2017-02-22 20:48:45 +0300658```text
Roman Elizarov1293ccd2017-02-01 18:49:54 +0300659The answer is 42
660Completed in 2017 ms
661```
662
Roman Elizarov35d2c342017-07-20 14:54:39 +0300663<!--- TEST ARBITRARY_TIME -->
Roman Elizarov731f0ad2017-02-22 20:48:45 +0300664
Roman Elizarov32d95322017-02-09 15:57:31 +0300665### Concurrent using async
Roman Elizarov1293ccd2017-02-01 18:49:54 +0300666
667What if there are no dependencies between invocation of `doSomethingUsefulOne` and `doSomethingUsefulTwo` and
Roman Elizarov419a6c82017-02-09 18:36:22 +0300668we want to get the answer faster, by doing both _concurrently_? This is where [async] comes to help.
Roman Elizarov1293ccd2017-02-01 18:49:54 +0300669
Roman Elizarov419a6c82017-02-09 18:36:22 +0300670Conceptually, [async] is just like [launch]. It starts a separate coroutine which is a light-weight thread
671that works concurrently with all the other coroutines. The difference is that `launch` returns a [Job] and
672does not carry any resulting value, while `async` returns a [Deferred] -- a light-weight non-blocking future
Roman Elizarov32d95322017-02-09 15:57:31 +0300673that represents a promise to provide a result later. You can use `.await()` on a deferred value to get its eventual result,
Roman Elizarov1293ccd2017-02-01 18:49:54 +0300674but `Deferred` is also a `Job`, so you can cancel it if needed.
675
676```kotlin
677fun main(args: Array<String>) = runBlocking<Unit> {
678 val time = measureTimeMillis {
Roman Elizarov66f018c2017-09-29 21:39:03 +0300679 val one = async { doSomethingUsefulOne() }
680 val two = async { doSomethingUsefulTwo() }
Roman Elizarov1293ccd2017-02-01 18:49:54 +0300681 println("The answer is ${one.await() + two.await()}")
682 }
683 println("Completed in $time ms")
684}
685```
686
Vsevolod Tolstopyatovc1eb19f2018-06-19 17:04:09 +0300687> You can get full code [here](core/kotlinx-coroutines-core/test/guide/example-compose-02.kt)
Roman Elizarov1293ccd2017-02-01 18:49:54 +0300688
689It produces something like this:
690
Roman Elizarov731f0ad2017-02-22 20:48:45 +0300691```text
Roman Elizarov1293ccd2017-02-01 18:49:54 +0300692The answer is 42
693Completed in 1017 ms
694```
695
Roman Elizarov35d2c342017-07-20 14:54:39 +0300696<!--- TEST ARBITRARY_TIME -->
Roman Elizarov731f0ad2017-02-22 20:48:45 +0300697
Roman Elizarov1293ccd2017-02-01 18:49:54 +0300698This is twice as fast, because we have concurrent execution of two coroutines.
699Note, that concurrency with coroutines is always explicit.
700
Roman Elizarov32d95322017-02-09 15:57:31 +0300701### Lazily started async
Roman Elizarov1293ccd2017-02-01 18:49:54 +0300702
Roman Elizarov66f018c2017-09-29 21:39:03 +0300703There is a laziness option to [async] using an optional `start` parameter with a value of [CoroutineStart.LAZY].
Roman Elizarov419a6c82017-02-09 18:36:22 +0300704It starts coroutine only when its result is needed by some
705[await][Deferred.await] or if a [start][Job.start] function
Sahil Lone52a0ec02018-07-19 18:55:35 +0200706is invoked. Run the following example:
Roman Elizarov1293ccd2017-02-01 18:49:54 +0300707
708```kotlin
709fun main(args: Array<String>) = runBlocking<Unit> {
710 val time = measureTimeMillis {
Roman Elizarov66f018c2017-09-29 21:39:03 +0300711 val one = async(start = CoroutineStart.LAZY) { doSomethingUsefulOne() }
712 val two = async(start = CoroutineStart.LAZY) { doSomethingUsefulTwo() }
Sahil Lone52a0ec02018-07-19 18:55:35 +0200713 // some computation
714 one.start() // start the first one
715 two.start() // start the second one
Roman Elizarov1293ccd2017-02-01 18:49:54 +0300716 println("The answer is ${one.await() + two.await()}")
717 }
718 println("Completed in $time ms")
719}
720```
721
Vsevolod Tolstopyatovc1eb19f2018-06-19 17:04:09 +0300722> You can get full code [here](core/kotlinx-coroutines-core/test/guide/example-compose-03.kt)
Roman Elizarov1293ccd2017-02-01 18:49:54 +0300723
724It produces something like this:
725
Roman Elizarov731f0ad2017-02-22 20:48:45 +0300726```text
Roman Elizarov1293ccd2017-02-01 18:49:54 +0300727The answer is 42
Sahil Lone52a0ec02018-07-19 18:55:35 +0200728Completed in 1017 ms
Roman Elizarov1293ccd2017-02-01 18:49:54 +0300729```
730
Roman Elizarov35d2c342017-07-20 14:54:39 +0300731<!--- TEST ARBITRARY_TIME -->
Roman Elizarov731f0ad2017-02-22 20:48:45 +0300732
Sahil Lone52a0ec02018-07-19 18:55:35 +0200733So, here the two coroutines are defined but not executed as in the previous example, but the control is given to
734the programmer about when exactly to start the execution by calling [start][Job.start] on it. We first
735start `one`, then start `two`, and then await for the individual coroutines to finish.
736
737Note, that if we have called [await][Deferred.await] in `println` and omitted [start][Job.start] on individual
738coroutines, then we would have got the sequential behaviour as [await][Deferred.await] starts the coroutine
739execution and waits for the execution to finish, which is not the intended use-case for laziness.
740The use-case for `async(start = CoroutineStart.LAZY)` is a replacement for the
741standard `lazy` function in cases when computation of the value involves suspending functions.
Roman Elizarov32d95322017-02-09 15:57:31 +0300742
743### Async-style functions
744
745We can define async-style functions that invoke `doSomethingUsefulOne` and `doSomethingUsefulTwo`
Roman Elizarov419a6c82017-02-09 18:36:22 +0300746_asynchronously_ using [async] coroutine builder. It is a good style to name such functions with
Marcin Moskała7e94e702018-01-29 18:39:02 +0100747"Async" suffix to highlight the fact that they only start asynchronous computation and one needs
748to use the resulting deferred value to get the result.
Roman Elizarov32d95322017-02-09 15:57:31 +0300749
750```kotlin
Marcin Moskała7e94e702018-01-29 18:39:02 +0100751// The result type of somethingUsefulOneAsync is Deferred<Int>
752fun somethingUsefulOneAsync() = async {
Roman Elizarov32d95322017-02-09 15:57:31 +0300753 doSomethingUsefulOne()
754}
755
Marcin Moskała7e94e702018-01-29 18:39:02 +0100756// The result type of somethingUsefulTwoAsync is Deferred<Int>
757fun somethingUsefulTwoAsync() = async {
Roman Elizarov32d95322017-02-09 15:57:31 +0300758 doSomethingUsefulTwo()
759}
760```
761
Marcin Moskała7e94e702018-01-29 18:39:02 +0100762Note, that these `xxxAsync` functions are **not** _suspending_ functions. They can be used from anywhere.
Roman Elizarov32d95322017-02-09 15:57:31 +0300763However, their use always implies asynchronous (here meaning _concurrent_) execution of their action
764with the invoking code.
765
766The following example shows their use outside of coroutine:
767
768```kotlin
769// note, that we don't have `runBlocking` to the right of `main` in this example
770fun main(args: Array<String>) {
771 val time = measureTimeMillis {
772 // we can initiate async actions outside of a coroutine
Marcin Moskała7e94e702018-01-29 18:39:02 +0100773 val one = somethingUsefulOneAsync()
774 val two = somethingUsefulTwoAsync()
Roman Elizarov32d95322017-02-09 15:57:31 +0300775 // but waiting for a result must involve either suspending or blocking.
776 // here we use `runBlocking { ... }` to block the main thread while waiting for the result
777 runBlocking {
778 println("The answer is ${one.await() + two.await()}")
779 }
780 }
781 println("Completed in $time ms")
782}
783```
784
Vsevolod Tolstopyatovc1eb19f2018-06-19 17:04:09 +0300785> You can get full code [here](core/kotlinx-coroutines-core/test/guide/example-compose-04.kt)
Roman Elizarov1293ccd2017-02-01 18:49:54 +0300786
Roman Elizarov35d2c342017-07-20 14:54:39 +0300787<!--- TEST ARBITRARY_TIME
Roman Elizarov731f0ad2017-02-22 20:48:45 +0300788The answer is 42
789Completed in 1085 ms
790-->
791
Roman Elizarov2f6d7c92017-02-03 15:16:07 +0300792## Coroutine context and dispatchers
793
Roman Elizarov66f018c2017-09-29 21:39:03 +0300794Coroutines always execute in some context which is represented by the value of
795[CoroutineContext](https://kotlinlang.org/api/latest/jvm/stdlib/kotlin.coroutines.experimental/-coroutine-context/)
796type, defined in the Kotlin standard library.
797
798The coroutine context is a set of various elements. The main elements are the [Job] of the coroutine,
799which we've seen before, and its dispatcher, which is covered in this section.
Roman Elizarov2f6d7c92017-02-03 15:16:07 +0300800
801### Dispatchers and threads
802
Roman Elizarov66f018c2017-09-29 21:39:03 +0300803Coroutine context includes a _coroutine dispatcher_ (see [CoroutineDispatcher]) that determines what thread or threads
Roman Elizarov2f6d7c92017-02-03 15:16:07 +0300804the corresponding coroutine uses for its execution. Coroutine dispatcher can confine coroutine execution
Roman Elizarov66f018c2017-09-29 21:39:03 +0300805to a specific thread, dispatch it to a thread pool, or let it run unconfined.
806
807All coroutines builders like [launch] and [async] accept an optional
808[CoroutineContext](https://kotlinlang.org/api/latest/jvm/stdlib/kotlin.coroutines.experimental/-coroutine-context/)
809parameter that can be used to explicitly specify the dispatcher for new coroutine and other context elements.
810
811Try the following example:
Roman Elizarov2f6d7c92017-02-03 15:16:07 +0300812
Roman Elizarov9fe5f462018-02-21 19:05:52 +0300813<!--- INCLUDE
814import kotlin.coroutines.experimental.*
815-->
816
Roman Elizarov2f6d7c92017-02-03 15:16:07 +0300817```kotlin
818fun main(args: Array<String>) = runBlocking<Unit> {
819 val jobs = arrayListOf<Job>()
820 jobs += launch(Unconfined) { // not confined -- will work with main thread
Roman Elizarov43e3af72017-07-21 16:01:31 +0300821 println(" 'Unconfined': I'm working in thread ${Thread.currentThread().name}")
Roman Elizarov2f6d7c92017-02-03 15:16:07 +0300822 }
Roman Elizarov43e3af72017-07-21 16:01:31 +0300823 jobs += launch(coroutineContext) { // context of the parent, runBlocking coroutine
824 println("'coroutineContext': I'm working in thread ${Thread.currentThread().name}")
Roman Elizarov2f6d7c92017-02-03 15:16:07 +0300825 }
826 jobs += launch(CommonPool) { // will get dispatched to ForkJoinPool.commonPool (or equivalent)
Roman Elizarov43e3af72017-07-21 16:01:31 +0300827 println(" 'CommonPool': I'm working in thread ${Thread.currentThread().name}")
Roman Elizarov2f6d7c92017-02-03 15:16:07 +0300828 }
829 jobs += launch(newSingleThreadContext("MyOwnThread")) { // will get its own new thread
Roman Elizarov43e3af72017-07-21 16:01:31 +0300830 println(" 'newSTC': I'm working in thread ${Thread.currentThread().name}")
Roman Elizarov2f6d7c92017-02-03 15:16:07 +0300831 }
832 jobs.forEach { it.join() }
833}
834```
835
Vsevolod Tolstopyatovc1eb19f2018-06-19 17:04:09 +0300836> You can get full code [here](core/kotlinx-coroutines-core/test/guide/example-context-01.kt)
Roman Elizarov2f6d7c92017-02-03 15:16:07 +0300837
838It produces the following output (maybe in different order):
839
Roman Elizarov731f0ad2017-02-22 20:48:45 +0300840```text
Roman Elizarov43e3af72017-07-21 16:01:31 +0300841 'Unconfined': I'm working in thread main
842 'CommonPool': I'm working in thread ForkJoinPool.commonPool-worker-1
843 'newSTC': I'm working in thread MyOwnThread
844'coroutineContext': I'm working in thread main
Roman Elizarov2f6d7c92017-02-03 15:16:07 +0300845```
846
Roman Elizarov731f0ad2017-02-22 20:48:45 +0300847<!--- TEST LINES_START_UNORDERED -->
848
Roman Elizarovd9ae2bc2017-10-20 17:36:56 +0800849The default dispatcher that we've used in previous sections is representend by [DefaultDispatcher], which
Roman Elizarov66f018c2017-09-29 21:39:03 +0300850is equal to [CommonPool] in the current implementation. So, `launch { ... }` is the same
Charles Muchenefa13beb2018-01-08 16:56:54 +0300851as `launch(DefaultDispatcher) { ... }`, which is the same as `launch(CommonPool) { ... }`.
Roman Elizarov66f018c2017-09-29 21:39:03 +0300852
Roman Elizarov9fe5f462018-02-21 19:05:52 +0300853The difference between parent
854[coroutineContext](https://kotlinlang.org/api/latest/jvm/stdlib/kotlin.coroutines.experimental/coroutine-context.html) and
Roman Elizarov43e3af72017-07-21 16:01:31 +0300855[Unconfined] context will be shown later.
Roman Elizarov2f6d7c92017-02-03 15:16:07 +0300856
Roman Elizarovd9ae2bc2017-10-20 17:36:56 +0800857Note, that [newSingleThreadContext] creates a new thread, which is a very expensive resource.
858In a real application it must be either released, when no longer needed, using [close][ThreadPoolDispatcher.close]
859function, or stored in a top-level variable and reused throughout the application.
860
Roman Elizarov2f6d7c92017-02-03 15:16:07 +0300861### Unconfined vs confined dispatcher
862
Roman Elizarov419a6c82017-02-09 18:36:22 +0300863The [Unconfined] coroutine dispatcher starts coroutine in the caller thread, but only until the
Roman Elizarov2f6d7c92017-02-03 15:16:07 +0300864first suspension point. After suspension it resumes in the thread that is fully determined by the
865suspending function that was invoked. Unconfined dispatcher is appropriate when coroutine does not
866consume CPU time nor updates any shared data (like UI) that is confined to a specific thread.
867
Roman Elizarov9fe5f462018-02-21 19:05:52 +0300868On the other side,
869[coroutineContext](https://kotlinlang.org/api/latest/jvm/stdlib/kotlin.coroutines.experimental/coroutine-context.html)
870property, that is available inside any coroutine, is a reference to a context of this particular coroutine.
Roman Elizarov66f018c2017-09-29 21:39:03 +0300871This way, a parent context can be inherited. The default dispatcher for [runBlocking] coroutine, in particular,
872is confined to the invoker thread, so inheriting it has the effect of confining execution to
Roman Elizarov2f6d7c92017-02-03 15:16:07 +0300873this thread with a predictable FIFO scheduling.
874
Roman Elizarov9fe5f462018-02-21 19:05:52 +0300875<!--- INCLUDE
876import kotlin.coroutines.experimental.*
877-->
878
Roman Elizarov2f6d7c92017-02-03 15:16:07 +0300879```kotlin
880fun main(args: Array<String>) = runBlocking<Unit> {
881 val jobs = arrayListOf<Job>()
882 jobs += launch(Unconfined) { // not confined -- will work with main thread
Roman Elizarov43e3af72017-07-21 16:01:31 +0300883 println(" 'Unconfined': I'm working in thread ${Thread.currentThread().name}")
Roman Elizarovd0021622017-03-10 15:43:38 +0300884 delay(500)
Roman Elizarov43e3af72017-07-21 16:01:31 +0300885 println(" 'Unconfined': After delay in thread ${Thread.currentThread().name}")
Roman Elizarov2f6d7c92017-02-03 15:16:07 +0300886 }
Roman Elizarov43e3af72017-07-21 16:01:31 +0300887 jobs += launch(coroutineContext) { // context of the parent, runBlocking coroutine
888 println("'coroutineContext': I'm working in thread ${Thread.currentThread().name}")
Roman Elizarov2f6d7c92017-02-03 15:16:07 +0300889 delay(1000)
Roman Elizarov43e3af72017-07-21 16:01:31 +0300890 println("'coroutineContext': After delay in thread ${Thread.currentThread().name}")
Roman Elizarov2f6d7c92017-02-03 15:16:07 +0300891 }
892 jobs.forEach { it.join() }
893}
894```
895
Vsevolod Tolstopyatovc1eb19f2018-06-19 17:04:09 +0300896> You can get full code [here](core/kotlinx-coroutines-core/test/guide/example-context-02.kt)
Roman Elizarov2f6d7c92017-02-03 15:16:07 +0300897
898Produces the output:
899
Roman Elizarov731f0ad2017-02-22 20:48:45 +0300900```text
Roman Elizarov43e3af72017-07-21 16:01:31 +0300901 'Unconfined': I'm working in thread main
902'coroutineContext': I'm working in thread main
903 'Unconfined': After delay in thread kotlinx.coroutines.DefaultExecutor
904'coroutineContext': After delay in thread main
Roman Elizarov2f6d7c92017-02-03 15:16:07 +0300905```
Roman Elizarov731f0ad2017-02-22 20:48:45 +0300906
907<!--- TEST LINES_START -->
Roman Elizarov2f6d7c92017-02-03 15:16:07 +0300908
Roman Elizarov43e3af72017-07-21 16:01:31 +0300909So, the coroutine that had inherited `coroutineContext` of `runBlocking {...}` continues to execute
910in the `main` thread, while the unconfined one had resumed in the default executor thread that [delay]
911function is using.
Roman Elizarov2f6d7c92017-02-03 15:16:07 +0300912
913### Debugging coroutines and threads
914
Roman Elizarov419a6c82017-02-09 18:36:22 +0300915Coroutines can suspend on one thread and resume on another thread with [Unconfined] dispatcher or
Roman Elizarov66f018c2017-09-29 21:39:03 +0300916with a default multi-threaded dispatcher. Even with a single-threaded dispatcher it might be hard to
paolopb019b102018-06-09 16:42:24 +0000917figure out what coroutine was doing, where, and when. The common approach to debugging applications with
Roman Elizarov2f6d7c92017-02-03 15:16:07 +0300918threads is to print the thread name in the log file on each log statement. This feature is universally supported
919by logging frameworks. When using coroutines, the thread name alone does not give much of a context, so
920`kotlinx.coroutines` includes debugging facilities to make it easier.
921
922Run the following code with `-Dkotlinx.coroutines.debug` JVM option:
923
Roman Elizarov9fe5f462018-02-21 19:05:52 +0300924<!--- INCLUDE
925import kotlin.coroutines.experimental.*
926-->
927
Roman Elizarov2f6d7c92017-02-03 15:16:07 +0300928```kotlin
929fun log(msg: String) = println("[${Thread.currentThread().name}] $msg")
930
931fun main(args: Array<String>) = runBlocking<Unit> {
Roman Elizarov43e3af72017-07-21 16:01:31 +0300932 val a = async(coroutineContext) {
Roman Elizarov2f6d7c92017-02-03 15:16:07 +0300933 log("I'm computing a piece of the answer")
934 6
935 }
Roman Elizarov43e3af72017-07-21 16:01:31 +0300936 val b = async(coroutineContext) {
Roman Elizarov2f6d7c92017-02-03 15:16:07 +0300937 log("I'm computing another piece of the answer")
938 7
939 }
940 log("The answer is ${a.await() * b.await()}")
941}
942```
943
Vsevolod Tolstopyatovc1eb19f2018-06-19 17:04:09 +0300944> You can get full code [here](core/kotlinx-coroutines-core/test/guide/example-context-03.kt)
Roman Elizarov2f6d7c92017-02-03 15:16:07 +0300945
Roman Elizarovb7721cf2017-02-03 19:23:08 +0300946There are three coroutines. The main coroutine (#1) -- `runBlocking` one,
Roman Elizarov2f6d7c92017-02-03 15:16:07 +0300947and two coroutines computing deferred values `a` (#2) and `b` (#3).
948They are all executing in the context of `runBlocking` and are confined to the main thread.
949The output of this code is:
950
Roman Elizarov731f0ad2017-02-22 20:48:45 +0300951```text
Roman Elizarov2f6d7c92017-02-03 15:16:07 +0300952[main @coroutine#2] I'm computing a piece of the answer
953[main @coroutine#3] I'm computing another piece of the answer
954[main @coroutine#1] The answer is 42
955```
956
Kirill Timofeeva5186962017-10-25 14:25:47 +0300957<!--- TEST FLEXIBLE_THREAD -->
Roman Elizarov731f0ad2017-02-22 20:48:45 +0300958
Roman Elizarov2f6d7c92017-02-03 15:16:07 +0300959The `log` function prints the name of the thread in square brackets and you can see, that it is the `main`
960thread, but the identifier of the currently executing coroutine is appended to it. This identifier
961is consecutively assigned to all created coroutines when debugging mode is turned on.
962
Roman Elizarov419a6c82017-02-09 18:36:22 +0300963You can read more about debugging facilities in the documentation for [newCoroutineContext] function.
Roman Elizarov2f6d7c92017-02-03 15:16:07 +0300964
965### Jumping between threads
966
967Run the following code with `-Dkotlinx.coroutines.debug` JVM option:
968
969```kotlin
970fun log(msg: String) = println("[${Thread.currentThread().name}] $msg")
971
972fun main(args: Array<String>) {
Roman Elizarovd9ae2bc2017-10-20 17:36:56 +0800973 newSingleThreadContext("Ctx1").use { ctx1 ->
974 newSingleThreadContext("Ctx2").use { ctx2 ->
975 runBlocking(ctx1) {
976 log("Started in ctx1")
Roman Elizarovf9e13f52017-12-21 12:23:15 +0300977 withContext(ctx2) {
Roman Elizarovd9ae2bc2017-10-20 17:36:56 +0800978 log("Working in ctx2")
979 }
980 log("Back to ctx1")
981 }
Roman Elizarov2f6d7c92017-02-03 15:16:07 +0300982 }
Roman Elizarov2f6d7c92017-02-03 15:16:07 +0300983 }
984}
985```
986
Vsevolod Tolstopyatovc1eb19f2018-06-19 17:04:09 +0300987> You can get full code [here](core/kotlinx-coroutines-core/test/guide/example-context-04.kt)
Roman Elizarov2f6d7c92017-02-03 15:16:07 +0300988
Roman Elizarovd9ae2bc2017-10-20 17:36:56 +0800989It demonstrates several new techniques. One is using [runBlocking] with an explicitly specified context, and
Roman Elizarovf9e13f52017-12-21 12:23:15 +0300990the other one is using [withContext] function to change a context of a coroutine while still staying in the
Roman Elizarov2f6d7c92017-02-03 15:16:07 +0300991same coroutine as you can see in the output below:
992
Roman Elizarov731f0ad2017-02-22 20:48:45 +0300993```text
Roman Elizarov2f6d7c92017-02-03 15:16:07 +0300994[Ctx1 @coroutine#1] Started in ctx1
995[Ctx2 @coroutine#1] Working in ctx2
996[Ctx1 @coroutine#1] Back to ctx1
997```
998
Roman Elizarov731f0ad2017-02-22 20:48:45 +0300999<!--- TEST -->
1000
Roman Elizarovd9ae2bc2017-10-20 17:36:56 +08001001
Artsiom Chapialioue185ed62018-06-03 19:34:22 -04001002Note, that this example also uses `use` function from the Kotlin standard library to release threads that
Roman Elizarovd9ae2bc2017-10-20 17:36:56 +08001003are created with [newSingleThreadContext] when they are no longer needed.
1004
Roman Elizarov2f6d7c92017-02-03 15:16:07 +03001005### Job in the context
1006
Roman Elizarov66f018c2017-09-29 21:39:03 +03001007The coroutine's [Job] is part of its context. The coroutine can retrieve it from its own context
Roman Elizarov43e3af72017-07-21 16:01:31 +03001008using `coroutineContext[Job]` expression:
Roman Elizarov2f6d7c92017-02-03 15:16:07 +03001009
Roman Elizarov9fe5f462018-02-21 19:05:52 +03001010<!--- INCLUDE
1011import kotlin.coroutines.experimental.*
1012-->
1013
Roman Elizarov2f6d7c92017-02-03 15:16:07 +03001014```kotlin
1015fun main(args: Array<String>) = runBlocking<Unit> {
Roman Elizarov43e3af72017-07-21 16:01:31 +03001016 println("My job is ${coroutineContext[Job]}")
Roman Elizarov2f6d7c92017-02-03 15:16:07 +03001017}
1018```
1019
Vsevolod Tolstopyatovc1eb19f2018-06-19 17:04:09 +03001020> You can get full code [here](core/kotlinx-coroutines-core/test/guide/example-context-05.kt)
Roman Elizarov2f6d7c92017-02-03 15:16:07 +03001021
Roman Elizarov66f018c2017-09-29 21:39:03 +03001022It produces something like that when running in [debug mode](#debugging-coroutines-and-threads):
Roman Elizarov2f6d7c92017-02-03 15:16:07 +03001023
1024```
Roman Elizarov8b38fa22017-09-27 17:44:31 +03001025My job is "coroutine#1":BlockingCoroutine{Active}@6d311334
Roman Elizarov2f6d7c92017-02-03 15:16:07 +03001026```
1027
Roman Elizarov8b38fa22017-09-27 17:44:31 +03001028<!--- TEST lines.size == 1 && lines[0].startsWith("My job is \"coroutine#1\":BlockingCoroutine{Active}@") -->
Roman Elizarov731f0ad2017-02-22 20:48:45 +03001029
Roman Elizarov43e3af72017-07-21 16:01:31 +03001030So, [isActive][CoroutineScope.isActive] in [CoroutineScope] is just a convenient shortcut for
Roman Elizarov9fe5f462018-02-21 19:05:52 +03001031`coroutineContext[Job]?.isActive == true`.
Roman Elizarov2f6d7c92017-02-03 15:16:07 +03001032
1033### Children of a coroutine
1034
Roman Elizarov9fe5f462018-02-21 19:05:52 +03001035When
1036[coroutineContext](https://kotlinlang.org/api/latest/jvm/stdlib/kotlin.coroutines.experimental/coroutine-context.html)
1037of a coroutine is used to launch another coroutine,
Roman Elizarov419a6c82017-02-09 18:36:22 +03001038the [Job] of the new coroutine becomes
Roman Elizarov2f6d7c92017-02-03 15:16:07 +03001039a _child_ of the parent coroutine's job. When the parent coroutine is cancelled, all its children
1040are recursively cancelled, too.
1041
Roman Elizarov9fe5f462018-02-21 19:05:52 +03001042<!--- INCLUDE
1043import kotlin.coroutines.experimental.*
1044-->
1045
Roman Elizarov2f6d7c92017-02-03 15:16:07 +03001046```kotlin
1047fun main(args: Array<String>) = runBlocking<Unit> {
Roman Elizarov66f018c2017-09-29 21:39:03 +03001048 // launch a coroutine to process some kind of incoming request
1049 val request = launch {
Roman Elizarov2f6d7c92017-02-03 15:16:07 +03001050 // it spawns two other jobs, one with its separate context
Roman Elizarov66f018c2017-09-29 21:39:03 +03001051 val job1 = launch {
Roman Elizarov2f6d7c92017-02-03 15:16:07 +03001052 println("job1: I have my own context and execute independently!")
1053 delay(1000)
1054 println("job1: I am not affected by cancellation of the request")
1055 }
1056 // and the other inherits the parent context
Roman Elizarov43e3af72017-07-21 16:01:31 +03001057 val job2 = launch(coroutineContext) {
Roman Elizarov74619c12017-11-09 10:32:15 +03001058 delay(100)
Roman Elizarov2f6d7c92017-02-03 15:16:07 +03001059 println("job2: I am a child of the request coroutine")
1060 delay(1000)
1061 println("job2: I will not execute this line if my parent request is cancelled")
1062 }
1063 // request completes when both its sub-jobs complete:
1064 job1.join()
1065 job2.join()
1066 }
1067 delay(500)
1068 request.cancel() // cancel processing of the request
1069 delay(1000) // delay a second to see what happens
1070 println("main: Who has survived request cancellation?")
1071}
1072```
1073
Vsevolod Tolstopyatovc1eb19f2018-06-19 17:04:09 +03001074> You can get full code [here](core/kotlinx-coroutines-core/test/guide/example-context-06.kt)
Roman Elizarov2f6d7c92017-02-03 15:16:07 +03001075
1076The output of this code is:
1077
Roman Elizarov731f0ad2017-02-22 20:48:45 +03001078```text
Roman Elizarov2f6d7c92017-02-03 15:16:07 +03001079job1: I have my own context and execute independently!
1080job2: I am a child of the request coroutine
1081job1: I am not affected by cancellation of the request
1082main: Who has survived request cancellation?
1083```
1084
Roman Elizarov731f0ad2017-02-22 20:48:45 +03001085<!--- TEST -->
1086
Roman Elizarov2f6d7c92017-02-03 15:16:07 +03001087### Combining contexts
1088
Roman Elizarov66f018c2017-09-29 21:39:03 +03001089Coroutine contexts can be combined using `+` operator. The context on the right-hand side replaces relevant entries
Roman Elizarov419a6c82017-02-09 18:36:22 +03001090of the context on the left-hand side. For example, a [Job] of the parent coroutine can be inherited, while
Roman Elizarov2f6d7c92017-02-03 15:16:07 +03001091its dispatcher replaced:
1092
Roman Elizarov9fe5f462018-02-21 19:05:52 +03001093<!--- INCLUDE
1094import kotlin.coroutines.experimental.*
1095-->
1096
Roman Elizarov2f6d7c92017-02-03 15:16:07 +03001097```kotlin
1098fun main(args: Array<String>) = runBlocking<Unit> {
1099 // start a coroutine to process some kind of incoming request
Roman Elizarov43e3af72017-07-21 16:01:31 +03001100 val request = launch(coroutineContext) { // use the context of `runBlocking`
Roman Elizarov2f6d7c92017-02-03 15:16:07 +03001101 // spawns CPU-intensive child job in CommonPool !!!
Roman Elizarov43e3af72017-07-21 16:01:31 +03001102 val job = launch(coroutineContext + CommonPool) {
Roman Elizarov2f6d7c92017-02-03 15:16:07 +03001103 println("job: I am a child of the request coroutine, but with a different dispatcher")
1104 delay(1000)
1105 println("job: I will not execute this line if my parent request is cancelled")
1106 }
1107 job.join() // request completes when its sub-job completes
1108 }
1109 delay(500)
1110 request.cancel() // cancel processing of the request
1111 delay(1000) // delay a second to see what happens
1112 println("main: Who has survived request cancellation?")
1113}
1114```
1115
Vsevolod Tolstopyatovc1eb19f2018-06-19 17:04:09 +03001116> You can get full code [here](core/kotlinx-coroutines-core/test/guide/example-context-07.kt)
Roman Elizarov2f6d7c92017-02-03 15:16:07 +03001117
1118The expected outcome of this code is:
1119
Roman Elizarov731f0ad2017-02-22 20:48:45 +03001120```text
Roman Elizarov2f6d7c92017-02-03 15:16:07 +03001121job: I am a child of the request coroutine, but with a different dispatcher
1122main: Who has survived request cancellation?
1123```
1124
Roman Elizarov731f0ad2017-02-22 20:48:45 +03001125<!--- TEST -->
1126
Roman Elizarov8b38fa22017-09-27 17:44:31 +03001127### Parental responsibilities
1128
1129A parent coroutine always waits for completion of all its children. Parent does not have to explicitly track
Roman Elizarov88396732017-09-27 21:30:47 +03001130all the children it launches and it does not have to use [Job.join] to wait for them at the end:
Roman Elizarov8b38fa22017-09-27 17:44:31 +03001131
Roman Elizarov9fe5f462018-02-21 19:05:52 +03001132<!--- INCLUDE
1133import kotlin.coroutines.experimental.*
1134-->
1135
Roman Elizarov8b38fa22017-09-27 17:44:31 +03001136```kotlin
1137fun main(args: Array<String>) = runBlocking<Unit> {
Roman Elizarov66f018c2017-09-29 21:39:03 +03001138 // launch a coroutine to process some kind of incoming request
1139 val request = launch {
Roman Elizarov8b38fa22017-09-27 17:44:31 +03001140 repeat(3) { i -> // launch a few children jobs
1141 launch(coroutineContext) {
1142 delay((i + 1) * 200L) // variable delay 200ms, 400ms, 600ms
1143 println("Coroutine $i is done")
1144 }
1145 }
1146 println("request: I'm done and I don't explicitly join my children that are still active")
1147 }
1148 request.join() // wait for completion of the request, including all its children
1149 println("Now processing of the request is complete")
1150}
1151```
1152
Vsevolod Tolstopyatovc1eb19f2018-06-19 17:04:09 +03001153> You can get full code [here](core/kotlinx-coroutines-core/test/guide/example-context-08.kt)
Roman Elizarov8b38fa22017-09-27 17:44:31 +03001154
1155The result is going to be:
1156
1157```text
1158request: I'm done and I don't explicitly join my children that are still active
1159Coroutine 0 is done
1160Coroutine 1 is done
1161Coroutine 2 is done
1162Now processing of the request is complete
1163```
1164
1165<!--- TEST -->
1166
Roman Elizarov2f6d7c92017-02-03 15:16:07 +03001167### Naming coroutines for debugging
1168
Roman Elizarovb7721cf2017-02-03 19:23:08 +03001169Automatically assigned ids are good when coroutines log often and you just need to correlate log records
Roman Elizarov2f6d7c92017-02-03 15:16:07 +03001170coming from the same coroutine. However, when coroutine is tied to the processing of a specific request
1171or doing some specific background task, it is better to name it explicitly for debugging purposes.
Roman Elizarov66f018c2017-09-29 21:39:03 +03001172[CoroutineName] context element serves the same function as a thread name. It'll get displayed in the thread name that
1173is executing this coroutine when [debugging mode](#debugging-coroutines-and-threads) is turned on.
Roman Elizarov2f6d7c92017-02-03 15:16:07 +03001174
1175The following example demonstrates this concept:
1176
1177```kotlin
1178fun log(msg: String) = println("[${Thread.currentThread().name}] $msg")
1179
1180fun main(args: Array<String>) = runBlocking(CoroutineName("main")) {
1181 log("Started main coroutine")
1182 // run two background value computations
Roman Elizarov66f018c2017-09-29 21:39:03 +03001183 val v1 = async(CoroutineName("v1coroutine")) {
Roman Elizarov2f6d7c92017-02-03 15:16:07 +03001184 delay(500)
Roman Elizarov674efea2017-10-21 17:16:30 +03001185 log("Computing v1")
Roman Elizarov2f6d7c92017-02-03 15:16:07 +03001186 252
1187 }
Roman Elizarov66f018c2017-09-29 21:39:03 +03001188 val v2 = async(CoroutineName("v2coroutine")) {
Roman Elizarov2f6d7c92017-02-03 15:16:07 +03001189 delay(1000)
Roman Elizarov674efea2017-10-21 17:16:30 +03001190 log("Computing v2")
Roman Elizarov2f6d7c92017-02-03 15:16:07 +03001191 6
1192 }
1193 log("The answer for v1 / v2 = ${v1.await() / v2.await()}")
1194}
1195```
1196
Vsevolod Tolstopyatovc1eb19f2018-06-19 17:04:09 +03001197> You can get full code [here](core/kotlinx-coroutines-core/test/guide/example-context-09.kt)
Roman Elizarov2f6d7c92017-02-03 15:16:07 +03001198
1199The output it produces with `-Dkotlinx.coroutines.debug` JVM option is similar to:
1200
Roman Elizarov731f0ad2017-02-22 20:48:45 +03001201```text
Roman Elizarov2f6d7c92017-02-03 15:16:07 +03001202[main @main#1] Started main coroutine
1203[ForkJoinPool.commonPool-worker-1 @v1coroutine#2] Computing v1
1204[ForkJoinPool.commonPool-worker-2 @v2coroutine#3] Computing v2
1205[main @main#1] The answer for v1 / v2 = 42
1206```
Roman Elizarov1293ccd2017-02-01 18:49:54 +03001207
Roman Elizarov731f0ad2017-02-22 20:48:45 +03001208<!--- TEST FLEXIBLE_THREAD -->
1209
Roman Elizarov2fd7cb32017-02-11 23:18:59 +03001210### Cancellation via explicit job
1211
1212Let us put our knowledge about contexts, children and jobs together. Assume that our application has
1213an object with a lifecycle, but that object is not a coroutine. For example, we are writing an Android application
1214and launch various coroutines in the context of an Android activity to perform asynchronous operations to fetch
1215and update data, do animations, etc. All of these coroutines must be cancelled when activity is destroyed
1216to avoid memory leaks.
1217
1218We can manage a lifecycle of our coroutines by creating an instance of [Job] that is tied to
Roman Elizarov88396732017-09-27 21:30:47 +03001219the lifecycle of our activity. A job instance is created using [Job()] factory function
Roman Elizarove8f694e2017-11-28 10:12:00 +03001220as the following example shows. For convenience, rather than using `launch(coroutineContext + job)` expression,
1221we can write `launch(coroutineContext, parent = job)` to make explicit the fact that the parent job is being used.
1222
1223Now, a single invocation of [Job.cancel] cancels all the children we've launched.
Roman Elizarov8b38fa22017-09-27 17:44:31 +03001224Moreover, [Job.join] waits for all of them to complete, so we can also use [cancelAndJoin] here in
1225this example:
Roman Elizarov2fd7cb32017-02-11 23:18:59 +03001226
Roman Elizarov9fe5f462018-02-21 19:05:52 +03001227<!--- INCLUDE
1228import kotlin.coroutines.experimental.*
1229-->
1230
Roman Elizarov2fd7cb32017-02-11 23:18:59 +03001231```kotlin
1232fun main(args: Array<String>) = runBlocking<Unit> {
1233 val job = Job() // create a job object to manage our lifecycle
1234 // now launch ten coroutines for a demo, each working for a different time
1235 val coroutines = List(10) { i ->
1236 // they are all children of our job object
Roman Elizarove8f694e2017-11-28 10:12:00 +03001237 launch(coroutineContext, parent = job) { // we use the context of main runBlocking thread, but with our parent job
Roman Elizarov8b38fa22017-09-27 17:44:31 +03001238 delay((i + 1) * 200L) // variable delay 200ms, 400ms, ... etc
Roman Elizarov2fd7cb32017-02-11 23:18:59 +03001239 println("Coroutine $i is done")
1240 }
1241 }
1242 println("Launched ${coroutines.size} coroutines")
1243 delay(500L) // delay for half a second
Roman Elizarov8b38fa22017-09-27 17:44:31 +03001244 println("Cancelling the job!")
1245 job.cancelAndJoin() // cancel all our coroutines and wait for all of them to complete
Roman Elizarov2fd7cb32017-02-11 23:18:59 +03001246}
1247```
1248
Vsevolod Tolstopyatovc1eb19f2018-06-19 17:04:09 +03001249> You can get full code [here](core/kotlinx-coroutines-core/test/guide/example-context-10.kt)
Roman Elizarov2fd7cb32017-02-11 23:18:59 +03001250
1251The output of this example is:
1252
Roman Elizarov731f0ad2017-02-22 20:48:45 +03001253```text
Roman Elizarov2fd7cb32017-02-11 23:18:59 +03001254Launched 10 coroutines
1255Coroutine 0 is done
1256Coroutine 1 is done
Roman Elizarov8b38fa22017-09-27 17:44:31 +03001257Cancelling the job!
Roman Elizarov2fd7cb32017-02-11 23:18:59 +03001258```
1259
Roman Elizarov731f0ad2017-02-22 20:48:45 +03001260<!--- TEST -->
1261
Roman Elizarov2fd7cb32017-02-11 23:18:59 +03001262As you can see, only the first three coroutines had printed a message and the others were cancelled
Roman Elizarov8b38fa22017-09-27 17:44:31 +03001263by a single invocation of `job.cancelAndJoin()`. So all we need to do in our hypothetical Android
Roman Elizarov2fd7cb32017-02-11 23:18:59 +03001264application is to create a parent job object when activity is created, use it for child coroutines,
Roman Elizarov8b38fa22017-09-27 17:44:31 +03001265and cancel it when activity is destroyed. We cannot `join` them in the case of Android lifecycle,
1266since it is synchronous, but this joining ability is useful when building backend services to ensure bounded
1267resource usage.
Roman Elizarov2fd7cb32017-02-11 23:18:59 +03001268
Vsevolod Tolstopyatov590696d2018-08-08 15:22:33 +03001269## Exception handling
1270
1271<!--- INCLUDE .*/example-exceptions-([0-9]+).kt
1272-->
1273
1274This section covers exception handling and cancellation on exceptions.
1275We already know that cancelled coroutine throws [CancellationException] in suspension points and that it
1276is ignored by coroutines machinery. But what happens if an exception is thrown during cancellation or multiple children of the same
1277coroutine throw an exception?
1278
1279### Exception propagation
1280Coroutine builders come in two flavors: propagating exceptions automatically ([launch] and [actor]) or exposing them to users ([async] and [produce]).
1281Former treat exceptions as unhandled, similar to Java's `Thread.uncaughExceptionHandler`, while the latter are relying on the user to consume the final
1282exception, for example via [await][Deferred.await] or [receive][ReceiveChannel.receive].
1283
1284It can be demonstrated by a simple example:
1285
1286<!--- INCLUDE
1287import kotlin.coroutines.experimental.*
1288-->
1289
1290```kotlin
1291fun main(args: Array<String>) = runBlocking {
1292 val job = launch {
1293 println("Throwing exception from launch")
1294 throw IndexOutOfBoundsException() // Will be printed to the console by Thread.defaultUncaughtExceptionHandler
1295 }
1296
1297 job.join()
1298 println("Joined failed job")
1299
1300 val deferred = async {
1301 println("Throwing exception from async")
1302 throw ArithmeticException() // Nothing is printed, relying on user to call await
1303 }
1304
1305 try {
1306 deferred.await()
1307 println("Unreached")
1308 } catch (e: ArithmeticException) {
1309 println("Caught ArithmeticException")
1310 }
1311}
1312```
1313
1314> You can get full code [here](core/kotlinx-coroutines-core/test/guide/example-exceptions-01.kt)
1315
1316The output of this code is:
1317
1318```text
1319Throwing exception from launch
1320Exception in thread "ForkJoinPool.commonPool-worker-2 @coroutine#2" java.lang.IndexOutOfBoundsException
1321Joined failed job
1322Throwing exception from async
1323Caught ArithmeticException
1324```
1325
1326<!--- TEST EXCEPTION-->
1327
1328
1329### CoroutineExceptionHandler
1330
1331But what if one does not want to print all exceptions to the console?
1332[CoroutineExceptionHandler] context element is used as generic `catch` block of coroutine where custom logging or exception handling may take place.
1333On JVM it's possible to redefine global exception handler for all coroutines by registering [CoroutineExceptionHandler] in `ServiceLoader`.
1334Global exception handler will be similar to `Thread.defaultUncaughtExceptionHandler`, which is used when no more specific handlers are registered.
1335On Android, `uncaughtExceptionPreHandler` is installed as a global coroutine exception handler.
1336
1337[CoroutineExceptionHandler] is invoked only on exceptions which are not expected to be handled by the user, so registering it in e.g. [async] builder has no effect
1338
1339<!--- INCLUDE
1340import kotlin.coroutines.experimental.*
1341-->
1342
1343```kotlin
1344fun main(args: Array<String>) = runBlocking {
1345 val handler = CoroutineExceptionHandler { _, exception -> println("Caught $exception") }
1346
1347 val job = launch(handler) {
1348 throw AssertionError()
1349 }
1350
1351 val deferred = async(handler) {
1352 throw ArithmeticException() // Nothing will be printed, relying on user to call deferred.await()
1353 }
1354
1355 joinAll(job, deferred)
1356}
1357```
1358
1359> You can get full code [here](core/kotlinx-coroutines-core/test/guide/example-exceptions-02.kt)
1360
1361The output of this code is:
1362
1363```text
1364Caught java.lang.AssertionError
1365```
1366
1367<!--- TEST-->
1368
1369### Cancellation and exceptions
1370Cancellation is tightly bound with exceptions. Coroutines use `CancellationException` for cancellation flow, these
1371exceptions are ignored by all handlers, so they should be used only as the source of additional debug information, which can
1372be obtained by `catch` block.
1373When coroutine is cancelled by using [Job.cancel] without a cause, it terminates, but doesn't cancel its parent.
1374Cancelling without cause is a mechanism for parent to cancel its children without accidental self-cancellation.
1375
1376<!--- INCLUDE
1377import kotlin.coroutines.experimental.*
1378-->
1379
1380```kotlin
1381fun main(args: Array<String>) = runBlocking {
1382 val job = launch(coroutineContext, parent = Job()) {
1383 val child = launch(coroutineContext) {
1384 try {
1385 delay(Long.MAX_VALUE)
1386 } finally {
1387 println("Child is cancelled")
1388 }
1389 }
1390
1391 yield()
1392 println("Cancelling child")
1393 child.cancel()
1394 child.join()
1395 yield()
1396 println("Parent is not cancelled")
1397 }
1398
1399 job.join()
1400}
1401```
1402
1403> You can get full code [here](core/kotlinx-coroutines-core/test/guide/example-exceptions-03.kt)
1404
1405The output of this code is:
1406
1407```text
1408Cancelling child
1409Child is cancelled
1410Parent is not cancelled
1411```
1412
1413<!--- TEST-->
1414
1415
1416If coroutine encounters exception other than `CancellationException`, it cancels its parent with that exception.
1417This behaviour cannot be overridden and is used to provide stable coroutines hierarchies which does not depend on [CoroutineExceptionHandler] implementation.
1418The original exception will be handled by the parent when all its children terminates.
1419<!--- INCLUDE
1420import kotlin.coroutines.experimental.*
1421-->
1422
1423```kotlin
1424fun main(args: Array<String>) = runBlocking {
1425 val handler = CoroutineExceptionHandler { _, exception -> println("Caught $exception") }
1426
1427 val job = launch(handler) {
1428 val child1 = launch(coroutineContext, start = CoroutineStart.ATOMIC) {
1429 try {
1430 delay(Long.MAX_VALUE)
1431 } finally {
1432 withContext(NonCancellable) {
1433 println("Children are cancelled, but exception is not handled until children are terminated completely")
1434 delay(100)
1435 println("Last child finished its non cancellable block")
1436 }
1437 }
1438 }
1439
1440 val child2 = launch(coroutineContext, start = CoroutineStart.ATOMIC) {
1441 delay(10)
1442 println("Child throws an exception")
1443 throw ArithmeticException()
1444 }
1445 }
1446
1447 job.join()
1448}
1449```
1450
1451> You can get full code [here](core/kotlinx-coroutines-core/test/guide/example-exceptions-04.kt)
1452
1453The output of this code is:
1454
1455```text
1456Child throws an exception
1457Children are cancelled, but exception is not handled until children are terminated completely
1458Last child finished its non cancellable block
1459Caught java.lang.ArithmeticException
1460```
1461<!--- TEST-->
1462
1463
1464### Exceptions aggregation
1465What happens if multiple children of a coroutine throw an exception?
1466The general rule is "the first exception wins", so the first thrown exception will be exposed to a handler.
1467But that may cause lost exceptions, for example if coroutine throws an exception during in its `finally` block.
1468One of the solutions is to report each exception separately, but then [Deferred.await] should have the same mechanism to avoid behavioural inconsistency.
1469To avoid that, we decided not to lose any exceptions, adding all exceptions to the suppressed exception of the original cause.
1470
1471<!--- INCLUDE
1472import kotlinx.coroutines.experimental.exceptions.*
1473import kotlin.coroutines.experimental.*
1474import java.io.*
1475-->
1476
1477```kotlin
1478fun main(args: Array<String>) = runBlocking {
1479 val handler = CoroutineExceptionHandler { _, exception ->
1480 println("Caught $exception with suppressed ${exception.suppressed().contentToString()}")
1481 }
1482
1483 val job = launch(handler + coroutineContext, parent = Job()) {
1484 launch(coroutineContext, start = CoroutineStart.ATOMIC) {
1485 try {
1486 delay(Long.MAX_VALUE)
1487 } finally {
1488 throw ArithmeticException()
1489 }
1490 }
1491
1492 launch(coroutineContext) {
1493 throw IOException()
1494 }
1495
1496 delay(Long.MAX_VALUE)
1497 }
1498
1499 job.join()
1500}
1501```
1502
1503> You can get full code [here](core/kotlinx-coroutines-core/test/guide/example-exceptions-05.kt)
1504
1505The output of this code is:
1506
1507```text
1508Caught java.io.IOException with suppressed [java.lang.ArithmeticException]
1509```
1510<!--- TEST-->
1511
1512
1513Note that this mechanism is currently works only on Java version 1.7+. Limitation on JS and Native is temporary and will be fixed in the future.
1514
1515Cancellation exceptions are transparent and unwrapped by default:
1516
1517<!--- INCLUDE
1518import kotlin.coroutines.experimental.*
1519import java.io.*
1520-->
1521
1522```kotlin
1523fun main(args: Array<String>) = runBlocking {
1524 val handler = CoroutineExceptionHandler { _, exception ->
1525 println("Caught original $exception")
1526 }
1527
1528 val job = launch(handler) {
1529 val inner = launch(coroutineContext) {
1530 launch(coroutineContext) {
1531 launch(coroutineContext) {
1532 throw IOException()
1533 }
1534 }
1535 }
1536
1537 try {
1538 inner.join()
1539 } catch (e: JobCancellationException) {
1540 println("Rethrowing JobCancellationException with original cause")
1541 throw e
1542 }
1543 }
1544
1545 job.join()
1546}
1547```
1548
1549> You can get full code [here](core/kotlinx-coroutines-core/test/guide/example-exceptions-06.kt)
1550
1551The output of this code is:
1552
1553```text
1554Rethrowing JobCancellationException with original cause
1555Caught original java.io.IOException
1556```
1557<!--- TEST-->
1558
Roman Elizarovb7721cf2017-02-03 19:23:08 +03001559## Channels
Roman Elizarov7deefb82017-01-31 10:33:17 +03001560
Roman Elizarovb7721cf2017-02-03 19:23:08 +03001561Deferred values provide a convenient way to transfer a single value between coroutines.
1562Channels provide a way to transfer a stream of values.
1563
1564<!--- INCLUDE .*/example-channel-([0-9]+).kt
1565import kotlinx.coroutines.experimental.channels.*
1566-->
1567
1568### Channel basics
1569
Roman Elizarov419a6c82017-02-09 18:36:22 +03001570A [Channel] is conceptually very similar to `BlockingQueue`. One key difference is that
1571instead of a blocking `put` operation it has a suspending [send][SendChannel.send], and instead of
1572a blocking `take` operation it has a suspending [receive][ReceiveChannel.receive].
Roman Elizarovb7721cf2017-02-03 19:23:08 +03001573
1574```kotlin
1575fun main(args: Array<String>) = runBlocking<Unit> {
1576 val channel = Channel<Int>()
Roman Elizarov66f018c2017-09-29 21:39:03 +03001577 launch {
Roman Elizarovb7721cf2017-02-03 19:23:08 +03001578 // this might be heavy CPU-consuming computation or async logic, we'll just send five squares
1579 for (x in 1..5) channel.send(x * x)
1580 }
1581 // here we print five received integers:
1582 repeat(5) { println(channel.receive()) }
1583 println("Done!")
1584}
1585```
1586
Vsevolod Tolstopyatovc1eb19f2018-06-19 17:04:09 +03001587> You can get full code [here](core/kotlinx-coroutines-core/test/guide/example-channel-01.kt)
Roman Elizarovb7721cf2017-02-03 19:23:08 +03001588
Roman Elizarov731f0ad2017-02-22 20:48:45 +03001589The output of this code is:
1590
1591```text
15921
15934
15949
159516
159625
1597Done!
1598```
1599
1600<!--- TEST -->
1601
Roman Elizarovb7721cf2017-02-03 19:23:08 +03001602### Closing and iteration over channels
1603
1604Unlike a queue, a channel can be closed to indicate that no more elements are coming.
1605On the receiver side it is convenient to use a regular `for` loop to receive elements
1606from the channel.
1607
Roman Elizarov419a6c82017-02-09 18:36:22 +03001608Conceptually, a [close][SendChannel.close] is like sending a special close token to the channel.
Roman Elizarovb7721cf2017-02-03 19:23:08 +03001609The iteration stops as soon as this close token is received, so there is a guarantee
1610that all previously sent elements before the close are received:
1611
1612```kotlin
1613fun main(args: Array<String>) = runBlocking<Unit> {
1614 val channel = Channel<Int>()
Roman Elizarov66f018c2017-09-29 21:39:03 +03001615 launch {
Roman Elizarovb7721cf2017-02-03 19:23:08 +03001616 for (x in 1..5) channel.send(x * x)
1617 channel.close() // we're done sending
1618 }
1619 // here we print received values using `for` loop (until the channel is closed)
1620 for (y in channel) println(y)
1621 println("Done!")
1622}
1623```
1624
Vsevolod Tolstopyatovc1eb19f2018-06-19 17:04:09 +03001625> You can get full code [here](core/kotlinx-coroutines-core/test/guide/example-channel-02.kt)
Roman Elizarovb7721cf2017-02-03 19:23:08 +03001626
Roman Elizarov731f0ad2017-02-22 20:48:45 +03001627<!--- TEST
16281
16294
16309
163116
163225
1633Done!
1634-->
1635
Roman Elizarovb7721cf2017-02-03 19:23:08 +03001636### Building channel producers
1637
Roman Elizarova5e653f2017-02-13 13:49:55 +03001638The pattern where a coroutine is producing a sequence of elements is quite common.
1639This is a part of _producer-consumer_ pattern that is often found in concurrent code.
Roman Elizarovb7721cf2017-02-03 19:23:08 +03001640You could abstract such a producer into a function that takes channel as its parameter, but this goes contrary
Roman Elizarova5e653f2017-02-13 13:49:55 +03001641to common sense that results must be returned from functions.
1642
Roman Elizarov86349be2017-03-17 16:47:37 +03001643There is a convenience coroutine builder named [produce] that makes it easy to do it right on producer side,
Roman Elizarov8b38fa22017-09-27 17:44:31 +03001644and an extension function [consumeEach], that replaces a `for` loop on the consumer side:
Roman Elizarovb7721cf2017-02-03 19:23:08 +03001645
1646```kotlin
Roman Elizarov66f018c2017-09-29 21:39:03 +03001647fun produceSquares() = produce<Int> {
Roman Elizarovb7721cf2017-02-03 19:23:08 +03001648 for (x in 1..5) send(x * x)
1649}
1650
1651fun main(args: Array<String>) = runBlocking<Unit> {
1652 val squares = produceSquares()
Roman Elizarov86349be2017-03-17 16:47:37 +03001653 squares.consumeEach { println(it) }
Roman Elizarovb7721cf2017-02-03 19:23:08 +03001654 println("Done!")
1655}
1656```
1657
Vsevolod Tolstopyatovc1eb19f2018-06-19 17:04:09 +03001658> You can get full code [here](core/kotlinx-coroutines-core/test/guide/example-channel-03.kt)
Roman Elizarovb7721cf2017-02-03 19:23:08 +03001659
Roman Elizarov731f0ad2017-02-22 20:48:45 +03001660<!--- TEST
16611
16624
16639
166416
166525
1666Done!
1667-->
1668
Roman Elizarovb7721cf2017-02-03 19:23:08 +03001669### Pipelines
1670
Roman Elizarov66f018c2017-09-29 21:39:03 +03001671A pipeline is a pattern where one coroutine is producing, possibly infinite, stream of values:
Roman Elizarovb7721cf2017-02-03 19:23:08 +03001672
1673```kotlin
Roman Elizarov66f018c2017-09-29 21:39:03 +03001674fun produceNumbers() = produce<Int> {
Roman Elizarovb7721cf2017-02-03 19:23:08 +03001675 var x = 1
1676 while (true) send(x++) // infinite stream of integers starting from 1
1677}
1678```
1679
Roman Elizarova5e653f2017-02-13 13:49:55 +03001680And another coroutine or coroutines are consuming that stream, doing some processing, and producing some other results.
Roman Elizarovb7721cf2017-02-03 19:23:08 +03001681In the below example the numbers are just squared:
1682
1683```kotlin
Roman Elizarov66f018c2017-09-29 21:39:03 +03001684fun square(numbers: ReceiveChannel<Int>) = produce<Int> {
Roman Elizarovb7721cf2017-02-03 19:23:08 +03001685 for (x in numbers) send(x * x)
1686}
1687```
1688
Roman Elizarova5e653f2017-02-13 13:49:55 +03001689The main code starts and connects the whole pipeline:
Roman Elizarovb7721cf2017-02-03 19:23:08 +03001690
1691```kotlin
1692fun main(args: Array<String>) = runBlocking<Unit> {
1693 val numbers = produceNumbers() // produces integers from 1 and on
1694 val squares = square(numbers) // squares integers
1695 for (i in 1..5) println(squares.receive()) // print first five
1696 println("Done!") // we are done
1697 squares.cancel() // need to cancel these coroutines in a larger app
1698 numbers.cancel()
1699}
1700```
1701
Vsevolod Tolstopyatovc1eb19f2018-06-19 17:04:09 +03001702> You can get full code [here](core/kotlinx-coroutines-core/test/guide/example-channel-04.kt)
Roman Elizarovb7721cf2017-02-03 19:23:08 +03001703
Roman Elizarov731f0ad2017-02-22 20:48:45 +03001704<!--- TEST
17051
17064
17079
170816
170925
1710Done!
1711-->
1712
Roman Elizarovb7721cf2017-02-03 19:23:08 +03001713We don't have to cancel these coroutines in this example app, because
1714[coroutines are like daemon threads](#coroutines-are-like-daemon-threads),
1715but in a larger app we'll need to stop our pipeline if we don't need it anymore.
1716Alternatively, we could have run pipeline coroutines as
Roman Elizarov66f018c2017-09-29 21:39:03 +03001717[children of a main coroutine](#children-of-a-coroutine) as is demonstrated in the following example.
Roman Elizarovb7721cf2017-02-03 19:23:08 +03001718
1719### Prime numbers with pipeline
1720
Cedric Beustfa0b28f2017-02-07 07:07:25 -08001721Let's take pipelines to the extreme with an example that generates prime numbers using a pipeline
Roman Elizarovb7721cf2017-02-03 19:23:08 +03001722of coroutines. We start with an infinite sequence of numbers. This time we introduce an
Roman Elizarov66f018c2017-09-29 21:39:03 +03001723explicit `context` parameter and pass it to [produce] builder,
1724so that caller can control where our coroutines run:
Roman Elizarovb7721cf2017-02-03 19:23:08 +03001725
Roman Elizarov9fe5f462018-02-21 19:05:52 +03001726<!--- INCLUDE
1727import kotlin.coroutines.experimental.*
Roman Elizarovb7721cf2017-02-03 19:23:08 +03001728-->
1729
1730```kotlin
Roman Elizarova5e653f2017-02-13 13:49:55 +03001731fun numbersFrom(context: CoroutineContext, start: Int) = produce<Int>(context) {
Roman Elizarovb7721cf2017-02-03 19:23:08 +03001732 var x = start
1733 while (true) send(x++) // infinite stream of integers from start
1734}
1735```
1736
1737The following pipeline stage filters an incoming stream of numbers, removing all the numbers
1738that are divisible by the given prime number:
1739
1740```kotlin
Roman Elizarova5e653f2017-02-13 13:49:55 +03001741fun filter(context: CoroutineContext, numbers: ReceiveChannel<Int>, prime: Int) = produce<Int>(context) {
Roman Elizarovb7721cf2017-02-03 19:23:08 +03001742 for (x in numbers) if (x % prime != 0) send(x)
1743}
1744```
1745
1746Now we build our pipeline by starting a stream of numbers from 2, taking a prime number from the current channel,
Roman Elizarov62500ba2017-02-09 18:55:40 +03001747and launching new pipeline stage for each prime number found:
1748
1749```
Roman Elizarova5e653f2017-02-13 13:49:55 +03001750numbersFrom(2) -> filter(2) -> filter(3) -> filter(5) -> filter(7) ...
Roman Elizarov62500ba2017-02-09 18:55:40 +03001751```
1752
1753The following example prints the first ten prime numbers,
Roman Elizarov8b38fa22017-09-27 17:44:31 +03001754running the whole pipeline in the context of the main thread. Since all the coroutines are launched as
Roman Elizarov9fe5f462018-02-21 19:05:52 +03001755children of the main [runBlocking] coroutine in its
1756[coroutineContext](https://kotlinlang.org/api/latest/jvm/stdlib/kotlin.coroutines.experimental/coroutine-context.html),
1757we don't have to keep an explicit list of all the coroutines we have started.
Roman Elizarov3e387b82017-12-04 13:49:11 +03001758We use [cancelChildren][kotlin.coroutines.experimental.CoroutineContext.cancelChildren]
1759extension function to cancel all the children coroutines.
Roman Elizarovb7721cf2017-02-03 19:23:08 +03001760
1761```kotlin
1762fun main(args: Array<String>) = runBlocking<Unit> {
Roman Elizarov43e3af72017-07-21 16:01:31 +03001763 var cur = numbersFrom(coroutineContext, 2)
Roman Elizarovb7721cf2017-02-03 19:23:08 +03001764 for (i in 1..10) {
1765 val prime = cur.receive()
1766 println(prime)
Roman Elizarov43e3af72017-07-21 16:01:31 +03001767 cur = filter(coroutineContext, cur, prime)
Roman Elizarovb7721cf2017-02-03 19:23:08 +03001768 }
Roman Elizarov8b38fa22017-09-27 17:44:31 +03001769 coroutineContext.cancelChildren() // cancel all children to let main finish
Roman Elizarovb7721cf2017-02-03 19:23:08 +03001770}
1771```
1772
Vsevolod Tolstopyatovc1eb19f2018-06-19 17:04:09 +03001773> You can get full code [here](core/kotlinx-coroutines-core/test/guide/example-channel-05.kt)
Roman Elizarovb7721cf2017-02-03 19:23:08 +03001774
1775The output of this code is:
1776
Roman Elizarov731f0ad2017-02-22 20:48:45 +03001777```text
Roman Elizarovb7721cf2017-02-03 19:23:08 +030017782
17793
17805
17817
178211
178313
178417
178519
178623
178729
1788```
1789
Roman Elizarov731f0ad2017-02-22 20:48:45 +03001790<!--- TEST -->
1791
Roman Elizarov66f018c2017-09-29 21:39:03 +03001792Note, that you can build the same pipeline using
1793[`buildIterator`](https://kotlinlang.org/api/latest/jvm/stdlib/kotlin.coroutines.experimental/build-iterator.html)
1794coroutine builder from the standard library.
Roman Elizarova5e653f2017-02-13 13:49:55 +03001795Replace `produce` with `buildIterator`, `send` with `yield`, `receive` with `next`,
Roman Elizarov62500ba2017-02-09 18:55:40 +03001796`ReceiveChannel` with `Iterator`, and get rid of the context. You will not need `runBlocking` either.
1797However, the benefit of a pipeline that uses channels as shown above is that it can actually use
1798multiple CPU cores if you run it in [CommonPool] context.
1799
Roman Elizarova5e653f2017-02-13 13:49:55 +03001800Anyway, this is an extremely impractical way to find prime numbers. In practice, pipelines do involve some
Roman Elizarov62500ba2017-02-09 18:55:40 +03001801other suspending invocations (like asynchronous calls to remote services) and these pipelines cannot be
1802built using `buildSeqeunce`/`buildIterator`, because they do not allow arbitrary suspension, unlike
Roman Elizarov66f018c2017-09-29 21:39:03 +03001803`produce`, which is fully asynchronous.
Roman Elizarov62500ba2017-02-09 18:55:40 +03001804
Roman Elizarovb7721cf2017-02-03 19:23:08 +03001805### Fan-out
1806
1807Multiple coroutines may receive from the same channel, distributing work between themselves.
1808Let us start with a producer coroutine that is periodically producing integers
1809(ten numbers per second):
1810
1811```kotlin
Roman Elizarov66f018c2017-09-29 21:39:03 +03001812fun produceNumbers() = produce<Int> {
Roman Elizarovb7721cf2017-02-03 19:23:08 +03001813 var x = 1 // start from 1
1814 while (true) {
1815 send(x++) // produce next
1816 delay(100) // wait 0.1s
1817 }
1818}
1819```
1820
1821Then we can have several processor coroutines. In this example, they just print their id and
1822received number:
1823
1824```kotlin
Roman Elizarov66f018c2017-09-29 21:39:03 +03001825fun launchProcessor(id: Int, channel: ReceiveChannel<Int>) = launch {
bill58c61c72018-06-21 17:24:08 -05001826 for (msg in channel) {
1827 println("Processor #$id received $msg")
Roman Elizarovec9384c2017-03-02 22:09:08 +03001828 }
Roman Elizarovb7721cf2017-02-03 19:23:08 +03001829}
1830```
1831
Roman Elizarov35d2c342017-07-20 14:54:39 +03001832Now let us launch five processors and let them work for almost a second. See what happens:
Roman Elizarovb7721cf2017-02-03 19:23:08 +03001833
1834```kotlin
1835fun main(args: Array<String>) = runBlocking<Unit> {
1836 val producer = produceNumbers()
1837 repeat(5) { launchProcessor(it, producer) }
Roman Elizarov35d2c342017-07-20 14:54:39 +03001838 delay(950)
Roman Elizarovb7721cf2017-02-03 19:23:08 +03001839 producer.cancel() // cancel producer coroutine and thus kill them all
1840}
1841```
1842
Vsevolod Tolstopyatovc1eb19f2018-06-19 17:04:09 +03001843> You can get full code [here](core/kotlinx-coroutines-core/test/guide/example-channel-06.kt)
Roman Elizarovb7721cf2017-02-03 19:23:08 +03001844
1845The output will be similar to the the following one, albeit the processor ids that receive
1846each specific integer may be different:
1847
1848```
1849Processor #2 received 1
1850Processor #4 received 2
1851Processor #0 received 3
1852Processor #1 received 4
1853Processor #3 received 5
1854Processor #2 received 6
1855Processor #4 received 7
1856Processor #0 received 8
1857Processor #1 received 9
1858Processor #3 received 10
1859```
1860
Roman Elizarov731f0ad2017-02-22 20:48:45 +03001861<!--- TEST lines.size == 10 && lines.withIndex().all { (i, line) -> line.startsWith("Processor #") && line.endsWith(" received ${i + 1}") } -->
1862
Roman Elizarovb7721cf2017-02-03 19:23:08 +03001863Note, that cancelling a producer coroutine closes its channel, thus eventually terminating iteration
1864over the channel that processor coroutines are doing.
1865
Roman Elizarov1ce6c0b2018-06-28 10:37:20 +03001866Also, pay attention to how we explicitly iterate over channel with `for` loop to perform fan-out in `launchProcessor` code.
1867Unlike `consumeEach`, this `for` loop pattern is perfectly safe to use from multiple coroutines. If one of the processor
1868coroutines fails, then others would still be processing the channel, while a processor that is written via `consumeEach`
1869always consumes (cancels) the underlying channel on its normal or abnormal termination.
1870
Roman Elizarovb7721cf2017-02-03 19:23:08 +03001871### Fan-in
1872
1873Multiple coroutines may send to the same channel.
1874For example, let us have a channel of strings, and a suspending function that
1875repeatedly sends a specified string to this channel with a specified delay:
1876
Roman Elizarov9fe5f462018-02-21 19:05:52 +03001877<!--- INCLUDE
1878import kotlin.coroutines.experimental.*
1879-->
1880
Roman Elizarovb7721cf2017-02-03 19:23:08 +03001881```kotlin
1882suspend fun sendString(channel: SendChannel<String>, s: String, time: Long) {
1883 while (true) {
1884 delay(time)
1885 channel.send(s)
1886 }
1887}
1888```
1889
Cedric Beustfa0b28f2017-02-07 07:07:25 -08001890Now, let us see what happens if we launch a couple of coroutines sending strings
Roman Elizarov8b38fa22017-09-27 17:44:31 +03001891(in this example we launch them in the context of the main thread as main coroutine's children):
Roman Elizarovb7721cf2017-02-03 19:23:08 +03001892
1893```kotlin
1894fun main(args: Array<String>) = runBlocking<Unit> {
1895 val channel = Channel<String>()
Roman Elizarov43e3af72017-07-21 16:01:31 +03001896 launch(coroutineContext) { sendString(channel, "foo", 200L) }
1897 launch(coroutineContext) { sendString(channel, "BAR!", 500L) }
Roman Elizarovb7721cf2017-02-03 19:23:08 +03001898 repeat(6) { // receive first six
1899 println(channel.receive())
1900 }
Roman Elizarov8b38fa22017-09-27 17:44:31 +03001901 coroutineContext.cancelChildren() // cancel all children to let main finish
Roman Elizarovb7721cf2017-02-03 19:23:08 +03001902}
1903```
1904
Vsevolod Tolstopyatovc1eb19f2018-06-19 17:04:09 +03001905> You can get full code [here](core/kotlinx-coroutines-core/test/guide/example-channel-07.kt)
Roman Elizarovb7721cf2017-02-03 19:23:08 +03001906
1907The output is:
1908
Roman Elizarov731f0ad2017-02-22 20:48:45 +03001909```text
Roman Elizarovb7721cf2017-02-03 19:23:08 +03001910foo
1911foo
1912BAR!
1913foo
1914foo
1915BAR!
1916```
1917
Roman Elizarov731f0ad2017-02-22 20:48:45 +03001918<!--- TEST -->
1919
Roman Elizarovb7721cf2017-02-03 19:23:08 +03001920### Buffered channels
1921
1922The channels shown so far had no buffer. Unbuffered channels transfer elements when sender and receiver
1923meet each other (aka rendezvous). If send is invoked first, then it is suspended until receive is invoked,
1924if receive is invoked first, it is suspended until send is invoked.
Roman Elizarov419a6c82017-02-09 18:36:22 +03001925
Roman Elizarov88396732017-09-27 21:30:47 +03001926Both [Channel()] factory function and [produce] builder take an optional `capacity` parameter to
Roman Elizarovb7721cf2017-02-03 19:23:08 +03001927specify _buffer size_. Buffer allows senders to send multiple elements before suspending,
1928similar to the `BlockingQueue` with a specified capacity, which blocks when buffer is full.
1929
1930Take a look at the behavior of the following code:
1931
Roman Elizarov9fe5f462018-02-21 19:05:52 +03001932<!--- INCLUDE
1933import kotlin.coroutines.experimental.*
1934-->
1935
Roman Elizarovb7721cf2017-02-03 19:23:08 +03001936```kotlin
1937fun main(args: Array<String>) = runBlocking<Unit> {
1938 val channel = Channel<Int>(4) // create buffered channel
Roman Elizarov8b38fa22017-09-27 17:44:31 +03001939 val sender = launch(coroutineContext) { // launch sender coroutine
Roman Elizarovb7721cf2017-02-03 19:23:08 +03001940 repeat(10) {
1941 println("Sending $it") // print before sending each element
1942 channel.send(it) // will suspend when buffer is full
1943 }
1944 }
1945 // don't receive anything... just wait....
1946 delay(1000)
Roman Elizarov8b38fa22017-09-27 17:44:31 +03001947 sender.cancel() // cancel sender coroutine
Roman Elizarovb7721cf2017-02-03 19:23:08 +03001948}
1949```
1950
Vsevolod Tolstopyatovc1eb19f2018-06-19 17:04:09 +03001951> You can get full code [here](core/kotlinx-coroutines-core/test/guide/example-channel-08.kt)
Roman Elizarovb7721cf2017-02-03 19:23:08 +03001952
1953It prints "sending" _five_ times using a buffered channel with capacity of _four_:
1954
Roman Elizarov731f0ad2017-02-22 20:48:45 +03001955```text
Roman Elizarovb7721cf2017-02-03 19:23:08 +03001956Sending 0
1957Sending 1
1958Sending 2
1959Sending 3
1960Sending 4
1961```
1962
Roman Elizarov731f0ad2017-02-22 20:48:45 +03001963<!--- TEST -->
1964
Roman Elizarovb7721cf2017-02-03 19:23:08 +03001965The first four elements are added to the buffer and the sender suspends when trying to send the fifth one.
Roman Elizarov419a6c82017-02-09 18:36:22 +03001966
Vsevolod Tolstopyatov03d2ff72018-05-29 17:28:20 +03001967### Ticker channels
Vsevolod Tolstopyatov1dbc25e2018-04-18 14:50:26 +03001968
Roman Elizarovb5328a72018-06-06 18:31:21 +03001969Ticker channel is a special rendezvous channel that produces `Unit` every time given delay passes since last consumption from this channel.
1970Though it may seem to be useless standalone, it is a useful building block to create complex time-based [produce]
Roman Elizarov0c090ed2018-06-29 19:51:07 +03001971pipelines and operators that do windowing and other time-dependent processing.
Roman Elizarovb5328a72018-06-06 18:31:21 +03001972Ticker channel can be used in [select] to perform "on tick" action.
Vsevolod Tolstopyatov1dbc25e2018-04-18 14:50:26 +03001973
Roman Elizarovb5328a72018-06-06 18:31:21 +03001974To create such channel use a factory method [ticker].
1975To indicate that no further elements are needed use [ReceiveChannel.cancel] method on it.
Vsevolod Tolstopyatov1dbc25e2018-04-18 14:50:26 +03001976
1977Now let's see how it works in practice:
Vsevolod Tolstopyatov1dbc25e2018-04-18 14:50:26 +03001978
1979```kotlin
1980fun main(args: Array<String>) = runBlocking<Unit> {
Roman Elizarovb5328a72018-06-06 18:31:21 +03001981 val tickerChannel = ticker(delay = 100, initialDelay = 0) // create ticker channel
Vsevolod Tolstopyatov03d2ff72018-05-29 17:28:20 +03001982 var nextElement = withTimeoutOrNull(1) { tickerChannel.receive() }
paolop1d6e4932018-07-02 08:46:34 +00001983 println("Initial element is available immediately: $nextElement") // initial delay hasn't passed yet
Vsevolod Tolstopyatov1dbc25e2018-04-18 14:50:26 +03001984
paolop1d6e4932018-07-02 08:46:34 +00001985 nextElement = withTimeoutOrNull(50) { tickerChannel.receive() } // all subsequent elements has 100ms delay
Vsevolod Tolstopyatov1dbc25e2018-04-18 14:50:26 +03001986 println("Next element is not ready in 50 ms: $nextElement")
1987
Roman Elizarovb5328a72018-06-06 18:31:21 +03001988 nextElement = withTimeoutOrNull(60) { tickerChannel.receive() }
Vsevolod Tolstopyatov1dbc25e2018-04-18 14:50:26 +03001989 println("Next element is ready in 100 ms: $nextElement")
1990
1991 // Emulate large consumption delays
Roman Elizarovb5328a72018-06-06 18:31:21 +03001992 println("Consumer pauses for 150ms")
Vsevolod Tolstopyatov1dbc25e2018-04-18 14:50:26 +03001993 delay(150)
1994 // Next element is available immediately
Vsevolod Tolstopyatov03d2ff72018-05-29 17:28:20 +03001995 nextElement = withTimeoutOrNull(1) { tickerChannel.receive() }
Vsevolod Tolstopyatov1dbc25e2018-04-18 14:50:26 +03001996 println("Next element is available immediately after large consumer delay: $nextElement")
1997 // Note that the pause between `receive` calls is taken into account and next element arrives faster
Roman Elizarovb5328a72018-06-06 18:31:21 +03001998 nextElement = withTimeoutOrNull(60) { tickerChannel.receive() }
Vsevolod Tolstopyatov1dbc25e2018-04-18 14:50:26 +03001999 println("Next element is ready in 50ms after consumer pause in 150ms: $nextElement")
2000
Vsevolod Tolstopyatov03d2ff72018-05-29 17:28:20 +03002001 tickerChannel.cancel() // indicate that no more elements are needed
Vsevolod Tolstopyatov1dbc25e2018-04-18 14:50:26 +03002002}
2003```
2004
Vsevolod Tolstopyatovc1eb19f2018-06-19 17:04:09 +03002005> You can get full code [here](core/kotlinx-coroutines-core/test/guide/example-channel-10.kt)
Vsevolod Tolstopyatov1dbc25e2018-04-18 14:50:26 +03002006
2007It prints following lines:
2008
2009```text
2010Initial element is available immediately: kotlin.Unit
2011Next element is not ready in 50 ms: null
2012Next element is ready in 100 ms: kotlin.Unit
Roman Elizarovb5328a72018-06-06 18:31:21 +03002013Consumer pauses for 150ms
Vsevolod Tolstopyatov1dbc25e2018-04-18 14:50:26 +03002014Next element is available immediately after large consumer delay: kotlin.Unit
2015Next element is ready in 50ms after consumer pause in 150ms: kotlin.Unit
2016```
2017
2018<!--- TEST -->
2019
Roman Elizarovb5328a72018-06-06 18:31:21 +03002020Note that [ticker] is aware of possible consumer pauses and, by default, adjusts next produced element
2021delay if a pause occurs, trying to maintain a fixed rate of produced elements.
2022
Roman Elizarov0c090ed2018-06-29 19:51:07 +03002023Optionally, a `mode` parameter equal to [TickerMode.FIXED_DELAY] can be specified to maintain a fixed
Roman Elizarovb5328a72018-06-06 18:31:21 +03002024delay between elements.
Vsevolod Tolstopyatov1dbc25e2018-04-18 14:50:26 +03002025
Roman Elizarovb0517ba2017-02-27 14:03:14 +03002026### Channels are fair
2027
2028Send and receive operations to channels are _fair_ with respect to the order of their invocation from
2029multiple coroutines. They are served in first-in first-out order, e.g. the first coroutine to invoke `receive`
2030gets the element. In the following example two coroutines "ping" and "pong" are
2031receiving the "ball" object from the shared "table" channel.
2032
Roman Elizarov9fe5f462018-02-21 19:05:52 +03002033<!--- INCLUDE
2034import kotlin.coroutines.experimental.*
2035-->
2036
Roman Elizarovb0517ba2017-02-27 14:03:14 +03002037```kotlin
2038data class Ball(var hits: Int)
2039
2040fun main(args: Array<String>) = runBlocking<Unit> {
2041 val table = Channel<Ball>() // a shared table
Roman Elizarov43e3af72017-07-21 16:01:31 +03002042 launch(coroutineContext) { player("ping", table) }
2043 launch(coroutineContext) { player("pong", table) }
Roman Elizarovb0517ba2017-02-27 14:03:14 +03002044 table.send(Ball(0)) // serve the ball
2045 delay(1000) // delay 1 second
Roman Elizarov8b38fa22017-09-27 17:44:31 +03002046 coroutineContext.cancelChildren() // game over, cancel them
Roman Elizarovb0517ba2017-02-27 14:03:14 +03002047}
2048
2049suspend fun player(name: String, table: Channel<Ball>) {
2050 for (ball in table) { // receive the ball in a loop
2051 ball.hits++
2052 println("$name $ball")
Roman Elizarovf526b132017-03-10 16:07:14 +03002053 delay(300) // wait a bit
Roman Elizarovb0517ba2017-02-27 14:03:14 +03002054 table.send(ball) // send the ball back
2055 }
2056}
2057```
2058
Vsevolod Tolstopyatovc1eb19f2018-06-19 17:04:09 +03002059> You can get full code [here](core/kotlinx-coroutines-core/test/guide/example-channel-09.kt)
Roman Elizarovb0517ba2017-02-27 14:03:14 +03002060
2061The "ping" coroutine is started first, so it is the first one to receive the ball. Even though "ping"
2062coroutine immediately starts receiving the ball again after sending it back to the table, the ball gets
2063received by the "pong" coroutine, because it was already waiting for it:
2064
2065```text
2066ping Ball(hits=1)
2067pong Ball(hits=2)
2068ping Ball(hits=3)
2069pong Ball(hits=4)
Roman Elizarovb0517ba2017-02-27 14:03:14 +03002070```
2071
2072<!--- TEST -->
2073
Roman Elizarov8b38fa22017-09-27 17:44:31 +03002074Note, that sometimes channels may produce executions that look unfair due to the nature of the executor
2075that is being used. See [this issue](https://github.com/Kotlin/kotlinx.coroutines/issues/111) for details.
2076
Roman Elizarovf5bc0472017-02-22 11:38:13 +03002077## Shared mutable state and concurrency
2078
Roman Elizarov66f018c2017-09-29 21:39:03 +03002079Coroutines can be executed concurrently using a multi-threaded dispatcher like the default [CommonPool]. It presents
Roman Elizarovf5bc0472017-02-22 11:38:13 +03002080all the usual concurrency problems. The main problem being synchronization of access to **shared mutable state**.
2081Some solutions to this problem in the land of coroutines are similar to the solutions in the multi-threaded world,
2082but others are unique.
2083
2084### The problem
2085
Roman Elizarov1e459602017-02-27 11:05:17 +03002086Let us launch a thousand coroutines all doing the same action thousand times (for a total of a million executions).
2087We'll also measure their completion time for further comparisons:
Roman Elizarovf5bc0472017-02-22 11:38:13 +03002088
Roman Elizarov1e459602017-02-27 11:05:17 +03002089<!--- INCLUDE .*/example-sync-03.kt
Roman Elizarov9fe5f462018-02-21 19:05:52 +03002090import java.util.concurrent.atomic.*
Roman Elizarovf5bc0472017-02-22 11:38:13 +03002091-->
2092
Roman Elizarov1e459602017-02-27 11:05:17 +03002093<!--- INCLUDE .*/example-sync-06.kt
Roman Elizarov9fe5f462018-02-21 19:05:52 +03002094import kotlinx.coroutines.experimental.sync.*
Roman Elizarovf5bc0472017-02-22 11:38:13 +03002095-->
2096
Roman Elizarov1e459602017-02-27 11:05:17 +03002097<!--- INCLUDE .*/example-sync-07.kt
Roman Elizarovf5bc0472017-02-22 11:38:13 +03002098import kotlinx.coroutines.experimental.channels.*
2099-->
2100
Roman Elizarov9fe5f462018-02-21 19:05:52 +03002101<!--- INCLUDE .*/example-sync-([0-9a-z]+).kt
2102import kotlin.system.*
2103import kotlin.coroutines.experimental.*
2104-->
2105
Roman Elizarovf5bc0472017-02-22 11:38:13 +03002106```kotlin
Roman Elizarov1e459602017-02-27 11:05:17 +03002107suspend fun massiveRun(context: CoroutineContext, action: suspend () -> Unit) {
2108 val n = 1000 // number of coroutines to launch
2109 val k = 1000 // times an action is repeated by each coroutine
Roman Elizarovf5bc0472017-02-22 11:38:13 +03002110 val time = measureTimeMillis {
2111 val jobs = List(n) {
Roman Elizarov1e459602017-02-27 11:05:17 +03002112 launch(context) {
2113 repeat(k) { action() }
Roman Elizarovf5bc0472017-02-22 11:38:13 +03002114 }
2115 }
2116 jobs.forEach { it.join() }
2117 }
Roman Elizarov1e459602017-02-27 11:05:17 +03002118 println("Completed ${n * k} actions in $time ms")
Roman Elizarovf5bc0472017-02-22 11:38:13 +03002119}
2120```
2121
Roman Elizarov43e90112017-05-10 11:25:20 +03002122<!--- INCLUDE .*/example-sync-([0-9a-z]+).kt -->
Roman Elizarovf5bc0472017-02-22 11:38:13 +03002123
Roman Elizarov1e459602017-02-27 11:05:17 +03002124We start with a very simple action that increments a shared mutable variable using
2125multi-threaded [CommonPool] context.
Roman Elizarovf5bc0472017-02-22 11:38:13 +03002126
2127```kotlin
2128var counter = 0
2129
2130fun main(args: Array<String>) = runBlocking<Unit> {
Roman Elizarov1e459602017-02-27 11:05:17 +03002131 massiveRun(CommonPool) {
Roman Elizarovf5bc0472017-02-22 11:38:13 +03002132 counter++
2133 }
2134 println("Counter = $counter")
2135}
2136```
2137
Vsevolod Tolstopyatovc1eb19f2018-06-19 17:04:09 +03002138> You can get full code [here](core/kotlinx-coroutines-core/test/guide/example-sync-01.kt)
Roman Elizarovf5bc0472017-02-22 11:38:13 +03002139
Roman Elizarov1e459602017-02-27 11:05:17 +03002140<!--- TEST LINES_START
2141Completed 1000000 actions in
2142Counter =
2143-->
Roman Elizarov731f0ad2017-02-22 20:48:45 +03002144
Roman Elizarov1e459602017-02-27 11:05:17 +03002145What does it print at the end? It is highly unlikely to ever print "Counter = 1000000", because a thousand coroutines
2146increment the `counter` concurrently from multiple threads without any synchronization.
2147
Roman Elizarov43e90112017-05-10 11:25:20 +03002148> Note: if you have an old system with 2 or fewer CPUs, then you _will_ consistently see 1000000, because
2149`CommonPool` is running in only one thread in this case. To reproduce the problem you'll need to make the
2150following change:
2151
2152```kotlin
2153val mtContext = newFixedThreadPoolContext(2, "mtPool") // explicitly define context with two threads
2154var counter = 0
2155
2156fun main(args: Array<String>) = runBlocking<Unit> {
2157 massiveRun(mtContext) { // use it instead of CommonPool in this sample and below
2158 counter++
2159 }
2160 println("Counter = $counter")
2161}
2162```
2163
Vsevolod Tolstopyatovc1eb19f2018-06-19 17:04:09 +03002164> You can get full code [here](core/kotlinx-coroutines-core/test/guide/example-sync-01b.kt)
Roman Elizarov43e90112017-05-10 11:25:20 +03002165
2166<!--- TEST LINES_START
2167Completed 1000000 actions in
2168Counter =
2169-->
2170
Roman Elizarov1e459602017-02-27 11:05:17 +03002171### Volatiles are of no help
2172
2173There is common misconception that making a variable `volatile` solves concurrency problem. Let us try it:
2174
2175```kotlin
2176@Volatile // in Kotlin `volatile` is an annotation
2177var counter = 0
2178
2179fun main(args: Array<String>) = runBlocking<Unit> {
2180 massiveRun(CommonPool) {
2181 counter++
2182 }
2183 println("Counter = $counter")
2184}
2185```
2186
Vsevolod Tolstopyatovc1eb19f2018-06-19 17:04:09 +03002187> You can get full code [here](core/kotlinx-coroutines-core/test/guide/example-sync-02.kt)
Roman Elizarov1e459602017-02-27 11:05:17 +03002188
2189<!--- TEST LINES_START
2190Completed 1000000 actions in
2191Counter =
2192-->
2193
2194This code works slower, but we still don't get "Counter = 1000000" at the end, because volatile variables guarantee
2195linearizable (this is a technical term for "atomic") reads and writes to the corresponding variable, but
2196do not provide atomicity of larger actions (increment in our case).
Roman Elizarovf5bc0472017-02-22 11:38:13 +03002197
2198### Thread-safe data structures
2199
2200The general solution that works both for threads and for coroutines is to use a thread-safe (aka synchronized,
2201linearizable, or atomic) data structure that provides all the necessarily synchronization for the corresponding
2202operations that needs to be performed on a shared state.
Roman Elizarov1e459602017-02-27 11:05:17 +03002203In the case of a simple counter we can use `AtomicInteger` class which has atomic `incrementAndGet` operations:
Roman Elizarovf5bc0472017-02-22 11:38:13 +03002204
2205```kotlin
2206var counter = AtomicInteger()
2207
2208fun main(args: Array<String>) = runBlocking<Unit> {
Roman Elizarov1e459602017-02-27 11:05:17 +03002209 massiveRun(CommonPool) {
Roman Elizarovf5bc0472017-02-22 11:38:13 +03002210 counter.incrementAndGet()
2211 }
2212 println("Counter = ${counter.get()}")
2213}
2214```
2215
Vsevolod Tolstopyatovc1eb19f2018-06-19 17:04:09 +03002216> You can get full code [here](core/kotlinx-coroutines-core/test/guide/example-sync-03.kt)
Roman Elizarovf5bc0472017-02-22 11:38:13 +03002217
Roman Elizarov1e459602017-02-27 11:05:17 +03002218<!--- TEST ARBITRARY_TIME
2219Completed 1000000 actions in xxx ms
2220Counter = 1000000
2221-->
Roman Elizarov731f0ad2017-02-22 20:48:45 +03002222
Roman Elizarovf5bc0472017-02-22 11:38:13 +03002223This is the fastest solution for this particular problem. It works for plain counters, collections, queues and other
2224standard data structures and basic operations on them. However, it does not easily scale to complex
2225state or to complex operations that do not have ready-to-use thread-safe implementations.
2226
Roman Elizarov1e459602017-02-27 11:05:17 +03002227### Thread confinement fine-grained
Roman Elizarovf5bc0472017-02-22 11:38:13 +03002228
Roman Elizarov1e459602017-02-27 11:05:17 +03002229_Thread confinement_ is an approach to the problem of shared mutable state where all access to the particular shared
Roman Elizarovf5bc0472017-02-22 11:38:13 +03002230state is confined to a single thread. It is typically used in UI applications, where all UI state is confined to
2231the single event-dispatch/application thread. It is easy to apply with coroutines by using a
2232single-threaded context:
2233
2234```kotlin
2235val counterContext = newSingleThreadContext("CounterContext")
2236var counter = 0
2237
2238fun main(args: Array<String>) = runBlocking<Unit> {
Roman Elizarov1e459602017-02-27 11:05:17 +03002239 massiveRun(CommonPool) { // run each coroutine in CommonPool
Roman Elizarovf9e13f52017-12-21 12:23:15 +03002240 withContext(counterContext) { // but confine each increment to the single-threaded context
Roman Elizarovf5bc0472017-02-22 11:38:13 +03002241 counter++
2242 }
2243 }
2244 println("Counter = $counter")
2245}
2246```
2247
Vsevolod Tolstopyatovc1eb19f2018-06-19 17:04:09 +03002248> You can get full code [here](core/kotlinx-coroutines-core/test/guide/example-sync-04.kt)
Roman Elizarovf5bc0472017-02-22 11:38:13 +03002249
Roman Elizarov1e459602017-02-27 11:05:17 +03002250<!--- TEST ARBITRARY_TIME
2251Completed 1000000 actions in xxx ms
2252Counter = 1000000
2253-->
2254
2255This code works very slowly, because it does _fine-grained_ thread-confinement. Each individual increment switches
Roman Elizarovf9e13f52017-12-21 12:23:15 +03002256from multi-threaded `CommonPool` context to the single-threaded context using [withContext] block.
Roman Elizarov1e459602017-02-27 11:05:17 +03002257
2258### Thread confinement coarse-grained
2259
2260In practice, thread confinement is performed in large chunks, e.g. big pieces of state-updating business logic
2261are confined to the single thread. The following example does it like that, running each coroutine in
2262the single-threaded context to start with.
2263
2264```kotlin
2265val counterContext = newSingleThreadContext("CounterContext")
2266var counter = 0
2267
2268fun main(args: Array<String>) = runBlocking<Unit> {
2269 massiveRun(counterContext) { // run each coroutine in the single-threaded context
2270 counter++
2271 }
2272 println("Counter = $counter")
2273}
2274```
2275
Vsevolod Tolstopyatovc1eb19f2018-06-19 17:04:09 +03002276> You can get full code [here](core/kotlinx-coroutines-core/test/guide/example-sync-05.kt)
Roman Elizarov1e459602017-02-27 11:05:17 +03002277
2278<!--- TEST ARBITRARY_TIME
2279Completed 1000000 actions in xxx ms
2280Counter = 1000000
2281-->
2282
2283This now works much faster and produces correct result.
Roman Elizarov731f0ad2017-02-22 20:48:45 +03002284
Roman Elizarovf5bc0472017-02-22 11:38:13 +03002285### Mutual exclusion
2286
2287Mutual exclusion solution to the problem is to protect all modifications of the shared state with a _critical section_
2288that is never executed concurrently. In a blocking world you'd typically use `synchronized` or `ReentrantLock` for that.
2289Coroutine's alternative is called [Mutex]. It has [lock][Mutex.lock] and [unlock][Mutex.unlock] functions to
paolop1d6e4932018-07-02 08:46:34 +00002290delimit a critical section. The key difference is that `Mutex.lock()` is a suspending function. It does not block a thread.
Roman Elizarovf5bc0472017-02-22 11:38:13 +03002291
Roman Elizarov88396732017-09-27 21:30:47 +03002292There is also [withLock] extension function that conveniently represents
Roman Elizarov8b38fa22017-09-27 17:44:31 +03002293`mutex.lock(); try { ... } finally { mutex.unlock() }` pattern:
2294
Roman Elizarovf5bc0472017-02-22 11:38:13 +03002295```kotlin
2296val mutex = Mutex()
2297var counter = 0
2298
2299fun main(args: Array<String>) = runBlocking<Unit> {
Roman Elizarov1e459602017-02-27 11:05:17 +03002300 massiveRun(CommonPool) {
Roman Elizarov8b38fa22017-09-27 17:44:31 +03002301 mutex.withLock {
2302 counter++
2303 }
Roman Elizarovf5bc0472017-02-22 11:38:13 +03002304 }
2305 println("Counter = $counter")
2306}
2307```
2308
Vsevolod Tolstopyatovc1eb19f2018-06-19 17:04:09 +03002309> You can get full code [here](core/kotlinx-coroutines-core/test/guide/example-sync-06.kt)
Roman Elizarovf5bc0472017-02-22 11:38:13 +03002310
Roman Elizarov1e459602017-02-27 11:05:17 +03002311<!--- TEST ARBITRARY_TIME
2312Completed 1000000 actions in xxx ms
2313Counter = 1000000
2314-->
2315
2316The locking in this example is fine-grained, so it pays the price. However, it is a good choice for some situations
2317where you absolutely must modify some shared state periodically, but there is no natural thread that this state
2318is confined to.
Roman Elizarov731f0ad2017-02-22 20:48:45 +03002319
Roman Elizarovf5bc0472017-02-22 11:38:13 +03002320### Actors
2321
paolop1d6e4932018-07-02 08:46:34 +00002322An [actor](https://en.wikipedia.org/wiki/Actor_model) is an entity made up of a combination of a coroutine, the state that is confined and encapsulated into this coroutine,
Roman Elizarovf5bc0472017-02-22 11:38:13 +03002323and a channel to communicate with other coroutines. A simple actor can be written as a function,
2324but an actor with a complex state is better suited for a class.
2325
Roman Elizarovc0e19f82017-02-27 11:59:14 +03002326There is an [actor] coroutine builder that conveniently combines actor's mailbox channel into its
2327scope to receive messages from and combines the send channel into the resulting job object, so that a
2328single reference to the actor can be carried around as its handle.
2329
Roman Elizarov256812a2017-07-22 01:00:30 +03002330The first step of using an actor is to define a class of messages that an actor is going to process.
2331Kotlin's [sealed classes](https://kotlinlang.org/docs/reference/sealed-classes.html) are well suited for that purpose.
2332We define `CounterMsg` sealed class with `IncCounter` message to increment a counter and `GetCounter` message
2333to get its value. The later needs to send a response. A [CompletableDeferred] communication
2334primitive, that represents a single value that will be known (communicated) in the future,
2335is used here for that purpose.
2336
Roman Elizarovf5bc0472017-02-22 11:38:13 +03002337```kotlin
2338// Message types for counterActor
2339sealed class CounterMsg
2340object IncCounter : CounterMsg() // one-way message to increment counter
Roman Elizarov256812a2017-07-22 01:00:30 +03002341class GetCounter(val response: CompletableDeferred<Int>) : CounterMsg() // a request with reply
2342```
Roman Elizarovf5bc0472017-02-22 11:38:13 +03002343
Roman Elizarov256812a2017-07-22 01:00:30 +03002344Then we define a function that launches an actor using an [actor] coroutine builder:
2345
2346```kotlin
Roman Elizarovf5bc0472017-02-22 11:38:13 +03002347// This function launches a new counter actor
Roman Elizarov66f018c2017-09-29 21:39:03 +03002348fun counterActor() = actor<CounterMsg> {
Roman Elizarovf5bc0472017-02-22 11:38:13 +03002349 var counter = 0 // actor state
Roman Elizarovc0e19f82017-02-27 11:59:14 +03002350 for (msg in channel) { // iterate over incoming messages
Roman Elizarovf5bc0472017-02-22 11:38:13 +03002351 when (msg) {
2352 is IncCounter -> counter++
Roman Elizarov256812a2017-07-22 01:00:30 +03002353 is GetCounter -> msg.response.complete(counter)
Roman Elizarovf5bc0472017-02-22 11:38:13 +03002354 }
2355 }
2356}
Roman Elizarov256812a2017-07-22 01:00:30 +03002357```
Roman Elizarovf5bc0472017-02-22 11:38:13 +03002358
Roman Elizarov256812a2017-07-22 01:00:30 +03002359The main code is straightforward:
2360
2361```kotlin
Roman Elizarovf5bc0472017-02-22 11:38:13 +03002362fun main(args: Array<String>) = runBlocking<Unit> {
Roman Elizarovc0e19f82017-02-27 11:59:14 +03002363 val counter = counterActor() // create the actor
Roman Elizarov1e459602017-02-27 11:05:17 +03002364 massiveRun(CommonPool) {
Roman Elizarovc0e19f82017-02-27 11:59:14 +03002365 counter.send(IncCounter)
Roman Elizarovf5bc0472017-02-22 11:38:13 +03002366 }
Roman Elizarov256812a2017-07-22 01:00:30 +03002367 // send a message to get a counter value from an actor
2368 val response = CompletableDeferred<Int>()
Roman Elizarovc0e19f82017-02-27 11:59:14 +03002369 counter.send(GetCounter(response))
Roman Elizarov256812a2017-07-22 01:00:30 +03002370 println("Counter = ${response.await()}")
Roman Elizarovc0e19f82017-02-27 11:59:14 +03002371 counter.close() // shutdown the actor
Roman Elizarovf5bc0472017-02-22 11:38:13 +03002372}
2373```
2374
Vsevolod Tolstopyatovc1eb19f2018-06-19 17:04:09 +03002375> You can get full code [here](core/kotlinx-coroutines-core/test/guide/example-sync-07.kt)
Roman Elizarovf5bc0472017-02-22 11:38:13 +03002376
Roman Elizarov1e459602017-02-27 11:05:17 +03002377<!--- TEST ARBITRARY_TIME
2378Completed 1000000 actions in xxx ms
2379Counter = 1000000
2380-->
Roman Elizarov731f0ad2017-02-22 20:48:45 +03002381
Roman Elizarovc0e19f82017-02-27 11:59:14 +03002382It does not matter (for correctness) what context the actor itself is executed in. An actor is
Roman Elizarovf5bc0472017-02-22 11:38:13 +03002383a coroutine and a coroutine is executed sequentially, so confinement of the state to the specific coroutine
paolop1d6e4932018-07-02 08:46:34 +00002384works as a solution to the problem of shared mutable state. Indeed, actors may modify their own private state, but can only affect each other through messages (avoiding the need for any locks).
Roman Elizarovf5bc0472017-02-22 11:38:13 +03002385
Roman Elizarovc0e19f82017-02-27 11:59:14 +03002386Actor is more efficient than locking under load, because in this case it always has work to do and it does not
2387have to switch to a different context at all.
2388
2389> Note, that an [actor] coroutine builder is a dual of [produce] coroutine builder. An actor is associated
2390 with the channel that it receives messages from, while a producer is associated with the channel that it
2391 sends elements to.
Roman Elizarov1e459602017-02-27 11:05:17 +03002392
Roman Elizarovd4dcbe22017-02-22 09:57:46 +03002393## Select expression
2394
Roman Elizarova84730b2017-02-22 11:58:50 +03002395Select expression makes it possible to await multiple suspending functions simultaneously and _select_
Roman Elizarovd4dcbe22017-02-22 09:57:46 +03002396the first one that becomes available.
2397
2398<!--- INCLUDE .*/example-select-([0-9]+).kt
2399import kotlinx.coroutines.experimental.channels.*
2400import kotlinx.coroutines.experimental.selects.*
2401-->
2402
2403### Selecting from channels
2404
Roman Elizarov57857202017-03-02 23:17:25 +03002405Let us have two producers of strings: `fizz` and `buzz`. The `fizz` produces "Fizz" string every 300 ms:
2406
Roman Elizarov9fe5f462018-02-21 19:05:52 +03002407<!--- INCLUDE
2408import kotlinx.coroutines.experimental.*
2409import kotlin.coroutines.experimental.*
Roman Elizarov57857202017-03-02 23:17:25 +03002410-->
2411
Roman Elizarovd4dcbe22017-02-22 09:57:46 +03002412```kotlin
Roman Elizarov57857202017-03-02 23:17:25 +03002413fun fizz(context: CoroutineContext) = produce<String>(context) {
2414 while (true) { // sends "Fizz" every 300 ms
Roman Elizarovd4dcbe22017-02-22 09:57:46 +03002415 delay(300)
2416 send("Fizz")
2417 }
2418}
2419```
2420
Roman Elizarov57857202017-03-02 23:17:25 +03002421And the `buzz` produces "Buzz!" string every 500 ms:
Roman Elizarovd4dcbe22017-02-22 09:57:46 +03002422
2423```kotlin
Roman Elizarov57857202017-03-02 23:17:25 +03002424fun buzz(context: CoroutineContext) = produce<String>(context) {
2425 while (true) { // sends "Buzz!" every 500 ms
Roman Elizarovd4dcbe22017-02-22 09:57:46 +03002426 delay(500)
2427 send("Buzz!")
2428 }
2429}
2430```
2431
2432Using [receive][ReceiveChannel.receive] suspending function we can receive _either_ from one channel or the
2433other. But [select] expression allows us to receive from _both_ simultaneously using its
Roman Elizarov8a5564d2017-09-06 18:48:22 +03002434[onReceive][ReceiveChannel.onReceive] clauses:
Roman Elizarovd4dcbe22017-02-22 09:57:46 +03002435
2436```kotlin
Roman Elizarov57857202017-03-02 23:17:25 +03002437suspend fun selectFizzBuzz(fizz: ReceiveChannel<String>, buzz: ReceiveChannel<String>) {
Roman Elizarovd4dcbe22017-02-22 09:57:46 +03002438 select<Unit> { // <Unit> means that this select expression does not produce any result
2439 fizz.onReceive { value -> // this is the first select clause
2440 println("fizz -> '$value'")
2441 }
2442 buzz.onReceive { value -> // this is the second select clause
2443 println("buzz -> '$value'")
2444 }
2445 }
2446}
2447```
2448
Roman Elizarov57857202017-03-02 23:17:25 +03002449Let us run it all seven times:
Roman Elizarovd4dcbe22017-02-22 09:57:46 +03002450
2451```kotlin
2452fun main(args: Array<String>) = runBlocking<Unit> {
Roman Elizarov43e3af72017-07-21 16:01:31 +03002453 val fizz = fizz(coroutineContext)
2454 val buzz = buzz(coroutineContext)
Roman Elizarovd4dcbe22017-02-22 09:57:46 +03002455 repeat(7) {
Roman Elizarov57857202017-03-02 23:17:25 +03002456 selectFizzBuzz(fizz, buzz)
Roman Elizarovd4dcbe22017-02-22 09:57:46 +03002457 }
Roman Elizarov8b38fa22017-09-27 17:44:31 +03002458 coroutineContext.cancelChildren() // cancel fizz & buzz coroutines
Roman Elizarovd4dcbe22017-02-22 09:57:46 +03002459}
2460```
2461
Vsevolod Tolstopyatovc1eb19f2018-06-19 17:04:09 +03002462> You can get full code [here](core/kotlinx-coroutines-core/test/guide/example-select-01.kt)
Roman Elizarovd4dcbe22017-02-22 09:57:46 +03002463
2464The result of this code is:
2465
Roman Elizarov731f0ad2017-02-22 20:48:45 +03002466```text
Roman Elizarovd4dcbe22017-02-22 09:57:46 +03002467fizz -> 'Fizz'
2468buzz -> 'Buzz!'
2469fizz -> 'Fizz'
2470fizz -> 'Fizz'
2471buzz -> 'Buzz!'
2472fizz -> 'Fizz'
2473buzz -> 'Buzz!'
2474```
2475
Roman Elizarov731f0ad2017-02-22 20:48:45 +03002476<!--- TEST -->
2477
Roman Elizarovd4dcbe22017-02-22 09:57:46 +03002478### Selecting on close
2479
paolop1d6e4932018-07-02 08:46:34 +00002480The [onReceive][ReceiveChannel.onReceive] clause in `select` fails when the channel is closed causing the corresponding
2481`select` to throw an exception. We can use [onReceiveOrNull][ReceiveChannel.onReceiveOrNull] clause to perform a
Roman Elizarova84730b2017-02-22 11:58:50 +03002482specific action when the channel is closed. The following example also shows that `select` is an expression that returns
Roman Elizarovd4dcbe22017-02-22 09:57:46 +03002483the result of its selected clause:
2484
Roman Elizarov9fe5f462018-02-21 19:05:52 +03002485<!--- INCLUDE
2486import kotlin.coroutines.experimental.*
2487-->
2488
Roman Elizarovd4dcbe22017-02-22 09:57:46 +03002489```kotlin
2490suspend fun selectAorB(a: ReceiveChannel<String>, b: ReceiveChannel<String>): String =
2491 select<String> {
2492 a.onReceiveOrNull { value ->
2493 if (value == null)
2494 "Channel 'a' is closed"
2495 else
2496 "a -> '$value'"
2497 }
2498 b.onReceiveOrNull { value ->
2499 if (value == null)
2500 "Channel 'b' is closed"
2501 else
2502 "b -> '$value'"
2503 }
2504 }
2505```
2506
Roman Elizarova84730b2017-02-22 11:58:50 +03002507Let's use it with channel `a` that produces "Hello" string four times and
2508channel `b` that produces "World" four times:
Roman Elizarovd4dcbe22017-02-22 09:57:46 +03002509
2510```kotlin
2511fun main(args: Array<String>) = runBlocking<Unit> {
2512 // we are using the context of the main thread in this example for predictability ...
Roman Elizarov43e3af72017-07-21 16:01:31 +03002513 val a = produce<String>(coroutineContext) {
Roman Elizarova84730b2017-02-22 11:58:50 +03002514 repeat(4) { send("Hello $it") }
Roman Elizarovd4dcbe22017-02-22 09:57:46 +03002515 }
Roman Elizarov43e3af72017-07-21 16:01:31 +03002516 val b = produce<String>(coroutineContext) {
Roman Elizarova84730b2017-02-22 11:58:50 +03002517 repeat(4) { send("World $it") }
Roman Elizarovd4dcbe22017-02-22 09:57:46 +03002518 }
2519 repeat(8) { // print first eight results
2520 println(selectAorB(a, b))
2521 }
Roman Elizarov8b38fa22017-09-27 17:44:31 +03002522 coroutineContext.cancelChildren()
Roman Elizarovd4dcbe22017-02-22 09:57:46 +03002523}
2524```
2525
Vsevolod Tolstopyatovc1eb19f2018-06-19 17:04:09 +03002526> You can get full code [here](core/kotlinx-coroutines-core/test/guide/example-select-02.kt)
Roman Elizarovd4dcbe22017-02-22 09:57:46 +03002527
Roman Elizarova84730b2017-02-22 11:58:50 +03002528The result of this code is quite interesting, so we'll analyze it in mode detail:
Roman Elizarovd4dcbe22017-02-22 09:57:46 +03002529
Roman Elizarov731f0ad2017-02-22 20:48:45 +03002530```text
Roman Elizarovd4dcbe22017-02-22 09:57:46 +03002531a -> 'Hello 0'
2532a -> 'Hello 1'
2533b -> 'World 0'
2534a -> 'Hello 2'
2535a -> 'Hello 3'
2536b -> 'World 1'
2537Channel 'a' is closed
2538Channel 'a' is closed
2539```
2540
Roman Elizarov731f0ad2017-02-22 20:48:45 +03002541<!--- TEST -->
2542
Roman Elizarova84730b2017-02-22 11:58:50 +03002543There are couple of observations to make out of it.
Roman Elizarovd4dcbe22017-02-22 09:57:46 +03002544
2545First of all, `select` is _biased_ to the first clause. When several clauses are selectable at the same time,
2546the first one among them gets selected. Here, both channels are constantly producing strings, so `a` channel,
Roman Elizarova84730b2017-02-22 11:58:50 +03002547being the first clause in select, wins. However, because we are using unbuffered channel, the `a` gets suspended from
Roman Elizarovd4dcbe22017-02-22 09:57:46 +03002548time to time on its [send][SendChannel.send] invocation and gives a chance for `b` to send, too.
2549
Roman Elizarov8a5564d2017-09-06 18:48:22 +03002550The second observation, is that [onReceiveOrNull][ReceiveChannel.onReceiveOrNull] gets immediately selected when the
Roman Elizarovd4dcbe22017-02-22 09:57:46 +03002551channel is already closed.
2552
2553### Selecting to send
2554
Roman Elizarov8a5564d2017-09-06 18:48:22 +03002555Select expression has [onSend][SendChannel.onSend] clause that can be used for a great good in combination
Roman Elizarovd4dcbe22017-02-22 09:57:46 +03002556with a biased nature of selection.
2557
Roman Elizarova84730b2017-02-22 11:58:50 +03002558Let us write an example of producer of integers that sends its values to a `side` channel when
Roman Elizarovd4dcbe22017-02-22 09:57:46 +03002559the consumers on its primary channel cannot keep up with it:
2560
Roman Elizarov8b38fa22017-09-27 17:44:31 +03002561<!--- INCLUDE
Roman Elizarov9fe5f462018-02-21 19:05:52 +03002562import kotlin.coroutines.experimental.*
Roman Elizarov8b38fa22017-09-27 17:44:31 +03002563-->
2564
Roman Elizarovd4dcbe22017-02-22 09:57:46 +03002565```kotlin
Roman Elizarov8b38fa22017-09-27 17:44:31 +03002566fun produceNumbers(context: CoroutineContext, side: SendChannel<Int>) = produce<Int>(context) {
Roman Elizarovd4dcbe22017-02-22 09:57:46 +03002567 for (num in 1..10) { // produce 10 numbers from 1 to 10
2568 delay(100) // every 100 ms
2569 select<Unit> {
Roman Elizarova84730b2017-02-22 11:58:50 +03002570 onSend(num) {} // Send to the primary channel
2571 side.onSend(num) {} // or to the side channel
Roman Elizarovd4dcbe22017-02-22 09:57:46 +03002572 }
2573 }
2574}
2575```
2576
2577Consumer is going to be quite slow, taking 250 ms to process each number:
Roman Elizarov9fe5f462018-02-21 19:05:52 +03002578
Roman Elizarovd4dcbe22017-02-22 09:57:46 +03002579```kotlin
2580fun main(args: Array<String>) = runBlocking<Unit> {
2581 val side = Channel<Int>() // allocate side channel
Roman Elizarov43e3af72017-07-21 16:01:31 +03002582 launch(coroutineContext) { // this is a very fast consumer for the side channel
Roman Elizarov86349be2017-03-17 16:47:37 +03002583 side.consumeEach { println("Side channel has $it") }
Roman Elizarovd4dcbe22017-02-22 09:57:46 +03002584 }
Roman Elizarov8b38fa22017-09-27 17:44:31 +03002585 produceNumbers(coroutineContext, side).consumeEach {
Roman Elizarov86349be2017-03-17 16:47:37 +03002586 println("Consuming $it")
Roman Elizarovd4dcbe22017-02-22 09:57:46 +03002587 delay(250) // let us digest the consumed number properly, do not hurry
2588 }
2589 println("Done consuming")
Roman Elizarov8b38fa22017-09-27 17:44:31 +03002590 coroutineContext.cancelChildren()
Roman Elizarovd4dcbe22017-02-22 09:57:46 +03002591}
2592```
2593
Vsevolod Tolstopyatovc1eb19f2018-06-19 17:04:09 +03002594> You can get full code [here](core/kotlinx-coroutines-core/test/guide/example-select-03.kt)
Roman Elizarovd4dcbe22017-02-22 09:57:46 +03002595
2596So let us see what happens:
2597
Roman Elizarov731f0ad2017-02-22 20:48:45 +03002598```text
Roman Elizarovd4dcbe22017-02-22 09:57:46 +03002599Consuming 1
2600Side channel has 2
2601Side channel has 3
2602Consuming 4
2603Side channel has 5
2604Side channel has 6
2605Consuming 7
2606Side channel has 8
2607Side channel has 9
2608Consuming 10
2609Done consuming
2610```
2611
Roman Elizarov731f0ad2017-02-22 20:48:45 +03002612<!--- TEST -->
2613
Roman Elizarovd4dcbe22017-02-22 09:57:46 +03002614### Selecting deferred values
2615
Roman Elizarov8a5564d2017-09-06 18:48:22 +03002616Deferred values can be selected using [onAwait][Deferred.onAwait] clause.
Roman Elizarova84730b2017-02-22 11:58:50 +03002617Let us start with an async function that returns a deferred string value after
Roman Elizarovd4dcbe22017-02-22 09:57:46 +03002618a random delay:
2619
2620<!--- INCLUDE .*/example-select-04.kt
2621import java.util.*
2622-->
2623
2624```kotlin
Roman Elizarov66f018c2017-09-29 21:39:03 +03002625fun asyncString(time: Int) = async {
Roman Elizarovd4dcbe22017-02-22 09:57:46 +03002626 delay(time.toLong())
2627 "Waited for $time ms"
2628}
2629```
2630
Roman Elizarova84730b2017-02-22 11:58:50 +03002631Let us start a dozen of them with a random delay.
Roman Elizarovd4dcbe22017-02-22 09:57:46 +03002632
2633```kotlin
2634fun asyncStringsList(): List<Deferred<String>> {
2635 val random = Random(3)
Roman Elizarova84730b2017-02-22 11:58:50 +03002636 return List(12) { asyncString(random.nextInt(1000)) }
Roman Elizarovd4dcbe22017-02-22 09:57:46 +03002637}
2638```
2639
Roman Elizarova84730b2017-02-22 11:58:50 +03002640Now the main function awaits for the first of them to complete and counts the number of deferred values
Roman Elizarovd4dcbe22017-02-22 09:57:46 +03002641that are still active. Note, that we've used here the fact that `select` expression is a Kotlin DSL,
Roman Elizarova84730b2017-02-22 11:58:50 +03002642so we can provide clauses for it using an arbitrary code. In this case we iterate over a list
2643of deferred values to provide `onAwait` clause for each deferred value.
Roman Elizarovd4dcbe22017-02-22 09:57:46 +03002644
2645```kotlin
2646fun main(args: Array<String>) = runBlocking<Unit> {
2647 val list = asyncStringsList()
2648 val result = select<String> {
2649 list.withIndex().forEach { (index, deferred) ->
2650 deferred.onAwait { answer ->
2651 "Deferred $index produced answer '$answer'"
2652 }
2653 }
2654 }
2655 println(result)
Roman Elizarov7c864d82017-02-27 10:17:50 +03002656 val countActive = list.count { it.isActive }
Roman Elizarovd4dcbe22017-02-22 09:57:46 +03002657 println("$countActive coroutines are still active")
2658}
2659```
2660
Vsevolod Tolstopyatovc1eb19f2018-06-19 17:04:09 +03002661> You can get full code [here](core/kotlinx-coroutines-core/test/guide/example-select-04.kt)
Roman Elizarovd4dcbe22017-02-22 09:57:46 +03002662
2663The output is:
2664
Roman Elizarov731f0ad2017-02-22 20:48:45 +03002665```text
Roman Elizarova84730b2017-02-22 11:58:50 +03002666Deferred 4 produced answer 'Waited for 128 ms'
Roman Elizarovd4dcbe22017-02-22 09:57:46 +0300266711 coroutines are still active
2668```
2669
Roman Elizarov731f0ad2017-02-22 20:48:45 +03002670<!--- TEST -->
2671
Roman Elizarovd4dcbe22017-02-22 09:57:46 +03002672### Switch over a channel of deferred values
2673
Roman Elizarova84730b2017-02-22 11:58:50 +03002674Let us write a channel producer function that consumes a channel of deferred string values, waits for each received
2675deferred value, but only until the next deferred value comes over or the channel is closed. This example puts together
Roman Elizarov8a5564d2017-09-06 18:48:22 +03002676[onReceiveOrNull][ReceiveChannel.onReceiveOrNull] and [onAwait][Deferred.onAwait] clauses in the same `select`:
Roman Elizarovd4dcbe22017-02-22 09:57:46 +03002677
Roman Elizarov9fe5f462018-02-21 19:05:52 +03002678<!--- INCLUDE
2679import kotlin.coroutines.experimental.*
2680-->
2681
Roman Elizarovd4dcbe22017-02-22 09:57:46 +03002682```kotlin
Roman Elizarov66f018c2017-09-29 21:39:03 +03002683fun switchMapDeferreds(input: ReceiveChannel<Deferred<String>>) = produce<String> {
Roman Elizarova84730b2017-02-22 11:58:50 +03002684 var current = input.receive() // start with first received deferred value
Roman Elizarovd4dcbe22017-02-22 09:57:46 +03002685 while (isActive) { // loop while not cancelled/closed
2686 val next = select<Deferred<String>?> { // return next deferred value from this select or null
2687 input.onReceiveOrNull { update ->
2688 update // replaces next value to wait
2689 }
2690 current.onAwait { value ->
2691 send(value) // send value that current deferred has produced
2692 input.receiveOrNull() // and use the next deferred from the input channel
2693 }
2694 }
2695 if (next == null) {
2696 println("Channel was closed")
2697 break // out of loop
2698 } else {
2699 current = next
2700 }
2701 }
2702}
2703```
2704
2705To test it, we'll use a simple async function that resolves to a specified string after a specified time:
2706
2707```kotlin
Roman Elizarov66f018c2017-09-29 21:39:03 +03002708fun asyncString(str: String, time: Long) = async {
Roman Elizarovd4dcbe22017-02-22 09:57:46 +03002709 delay(time)
2710 str
2711}
2712```
2713
2714The main function just launches a coroutine to print results of `switchMapDeferreds` and sends some test
2715data to it:
2716
2717```kotlin
2718fun main(args: Array<String>) = runBlocking<Unit> {
2719 val chan = Channel<Deferred<String>>() // the channel for test
Roman Elizarov43e3af72017-07-21 16:01:31 +03002720 launch(coroutineContext) { // launch printing coroutine
Roman Elizarovd4dcbe22017-02-22 09:57:46 +03002721 for (s in switchMapDeferreds(chan))
2722 println(s) // print each received string
2723 }
2724 chan.send(asyncString("BEGIN", 100))
2725 delay(200) // enough time for "BEGIN" to be produced
2726 chan.send(asyncString("Slow", 500))
Roman Elizarova84730b2017-02-22 11:58:50 +03002727 delay(100) // not enough time to produce slow
Roman Elizarovd4dcbe22017-02-22 09:57:46 +03002728 chan.send(asyncString("Replace", 100))
Roman Elizarova84730b2017-02-22 11:58:50 +03002729 delay(500) // give it time before the last one
Roman Elizarovd4dcbe22017-02-22 09:57:46 +03002730 chan.send(asyncString("END", 500))
2731 delay(1000) // give it time to process
Roman Elizarova84730b2017-02-22 11:58:50 +03002732 chan.close() // close the channel ...
Roman Elizarovd4dcbe22017-02-22 09:57:46 +03002733 delay(500) // and wait some time to let it finish
2734}
2735```
2736
Vsevolod Tolstopyatovc1eb19f2018-06-19 17:04:09 +03002737> You can get full code [here](core/kotlinx-coroutines-core/test/guide/example-select-05.kt)
Roman Elizarovd4dcbe22017-02-22 09:57:46 +03002738
2739The result of this code:
2740
Roman Elizarov731f0ad2017-02-22 20:48:45 +03002741```text
Roman Elizarovd4dcbe22017-02-22 09:57:46 +03002742BEGIN
2743Replace
2744END
2745Channel was closed
2746```
2747
Roman Elizarov731f0ad2017-02-22 20:48:45 +03002748<!--- TEST -->
Roman Elizarovd4dcbe22017-02-22 09:57:46 +03002749
Roman Elizarov8db17332017-03-09 12:40:45 +03002750## Further reading
2751
2752* [Guide to UI programming with coroutines](ui/coroutines-guide-ui.md)
Roman Elizarov8a4a8e12017-03-09 19:52:58 +03002753* [Guide to reactive streams with coroutines](reactive/coroutines-guide-reactive.md)
Roman Elizarov8db17332017-03-09 12:40:45 +03002754* [Coroutines design document (KEEP)](https://github.com/Kotlin/kotlin-coroutines/blob/master/kotlin-coroutines-informal.md)
2755* [Full kotlinx.coroutines API reference](http://kotlin.github.io/kotlinx.coroutines)
2756
Roman Elizarove7e2ad12017-05-17 14:47:31 +03002757<!--- MODULE kotlinx-coroutines-core -->
Roman Elizarove0c817d2017-02-10 10:22:01 +03002758<!--- INDEX kotlinx.coroutines.experimental -->
Roman Elizarovd4dcbe22017-02-22 09:57:46 +03002759[launch]: https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines.experimental/launch.html
2760[delay]: https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines.experimental/delay.html
2761[runBlocking]: https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines.experimental/run-blocking.html
Roman Elizarove82dee72017-08-18 16:49:09 +03002762[Job]: https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines.experimental/-job/index.html
Roman Elizarov8b38fa22017-09-27 17:44:31 +03002763[cancelAndJoin]: https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines.experimental/cancel-and-join.html
Roman Elizarov88396732017-09-27 21:30:47 +03002764[Job.cancel]: https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines.experimental/-job/cancel.html
2765[Job.join]: https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines.experimental/-job/join.html
Roman Elizarovcbb602d2017-12-23 14:24:26 +03002766[CancellationException]: https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines.experimental/-cancellation-exception/index.html
Roman Elizarovd4dcbe22017-02-22 09:57:46 +03002767[yield]: https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines.experimental/yield.html
Roman Elizarovbff3f372017-03-01 18:12:27 +03002768[CoroutineScope.isActive]: https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines.experimental/-coroutine-scope/is-active.html
Roman Elizarovd4dcbe22017-02-22 09:57:46 +03002769[CoroutineScope]: https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines.experimental/-coroutine-scope/index.html
Roman Elizarovf9e13f52017-12-21 12:23:15 +03002770[withContext]: https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines.experimental/with-context.html
Roman Elizarovd4dcbe22017-02-22 09:57:46 +03002771[NonCancellable]: https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines.experimental/-non-cancellable/index.html
2772[withTimeout]: https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines.experimental/with-timeout.html
Roman Elizarov63f6ea22017-09-06 18:42:34 +03002773[withTimeoutOrNull]: https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines.experimental/with-timeout-or-null.html
Roman Elizarovd4dcbe22017-02-22 09:57:46 +03002774[async]: https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines.experimental/async.html
2775[Deferred]: https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines.experimental/-deferred/index.html
Roman Elizarovecda27f2017-04-06 23:06:26 +03002776[CoroutineStart.LAZY]: https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines.experimental/-coroutine-start/-l-a-z-y.html
Roman Elizarovbff3f372017-03-01 18:12:27 +03002777[Deferred.await]: https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines.experimental/-deferred/await.html
2778[Job.start]: https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines.experimental/-job/start.html
Roman Elizarov419a6c82017-02-09 18:36:22 +03002779[CoroutineDispatcher]: https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines.experimental/-coroutine-dispatcher/index.html
Roman Elizarovd9ae2bc2017-10-20 17:36:56 +08002780[DefaultDispatcher]: https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines.experimental/-default-dispatcher.html
Roman Elizarov66f018c2017-09-29 21:39:03 +03002781[CommonPool]: https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines.experimental/-common-pool/index.html
Roman Elizarov419a6c82017-02-09 18:36:22 +03002782[Unconfined]: https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines.experimental/-unconfined/index.html
Roman Elizarovd9ae2bc2017-10-20 17:36:56 +08002783[newSingleThreadContext]: https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines.experimental/new-single-thread-context.html
2784[ThreadPoolDispatcher.close]: https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines.experimental/-thread-pool-dispatcher/close.html
Roman Elizarov419a6c82017-02-09 18:36:22 +03002785[newCoroutineContext]: https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines.experimental/new-coroutine-context.html
Roman Elizarovd4dcbe22017-02-22 09:57:46 +03002786[CoroutineName]: https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines.experimental/-coroutine-name/index.html
Roman Elizarov88396732017-09-27 21:30:47 +03002787[Job()]: https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines.experimental/-job.html
Vsevolod Tolstopyatov590696d2018-08-08 15:22:33 +03002788[CoroutineExceptionHandler]: https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines.experimental/-coroutine-exception-handler/index.html
Roman Elizarov3e387b82017-12-04 13:49:11 +03002789[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
Roman Elizarove82dee72017-08-18 16:49:09 +03002790[CompletableDeferred]: https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines.experimental/-completable-deferred/index.html
Roman Elizarov8a5564d2017-09-06 18:48:22 +03002791[Deferred.onAwait]: https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines.experimental/-deferred/on-await.html
Roman Elizarovf5bc0472017-02-22 11:38:13 +03002792<!--- INDEX kotlinx.coroutines.experimental.sync -->
Roman Elizarove82dee72017-08-18 16:49:09 +03002793[Mutex]: https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines.experimental.sync/-mutex/index.html
Roman Elizarovbff3f372017-03-01 18:12:27 +03002794[Mutex.lock]: https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines.experimental.sync/-mutex/lock.html
2795[Mutex.unlock]: https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines.experimental.sync/-mutex/unlock.html
Roman Elizarov88396732017-09-27 21:30:47 +03002796[withLock]: https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines.experimental.sync/with-lock.html
Roman Elizarove0c817d2017-02-10 10:22:01 +03002797<!--- INDEX kotlinx.coroutines.experimental.channels -->
Vsevolod Tolstopyatov590696d2018-08-08 15:22:33 +03002798[actor]: https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines.experimental.channels/actor.html
2799[produce]: https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines.experimental.channels/produce.html
2800[ReceiveChannel.receive]: https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines.experimental.channels/-receive-channel/receive.html
Roman Elizarove82dee72017-08-18 16:49:09 +03002801[Channel]: https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines.experimental.channels/-channel/index.html
Roman Elizarovbff3f372017-03-01 18:12:27 +03002802[SendChannel.send]: https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines.experimental.channels/-send-channel/send.html
Roman Elizarovbff3f372017-03-01 18:12:27 +03002803[SendChannel.close]: https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines.experimental.channels/-send-channel/close.html
Roman Elizarov86349be2017-03-17 16:47:37 +03002804[consumeEach]: https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines.experimental.channels/consume-each.html
Roman Elizarov88396732017-09-27 21:30:47 +03002805[Channel()]: https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines.experimental.channels/-channel.html
Vsevolod Tolstopyatov03d2ff72018-05-29 17:28:20 +03002806[ticker]: https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines.experimental.channels/ticker.html
Vsevolod Tolstopyatov1dbc25e2018-04-18 14:50:26 +03002807[ReceiveChannel.cancel]: https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines.experimental.channels/-receive-channel/cancel.html
Roman Elizarov0c090ed2018-06-29 19:51:07 +03002808[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 Elizarovb5328a72018-06-06 18:31:21 +03002809[ReceiveChannel.onReceive]: https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines.experimental.channels/-receive-channel/on-receive.html
Roman Elizarov8a5564d2017-09-06 18:48:22 +03002810[ReceiveChannel.onReceiveOrNull]: https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines.experimental.channels/-receive-channel/on-receive-or-null.html
2811[SendChannel.onSend]: https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines.experimental.channels/-send-channel/on-send.html
Roman Elizarovd4dcbe22017-02-22 09:57:46 +03002812<!--- INDEX kotlinx.coroutines.experimental.selects -->
2813[select]: https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines.experimental.selects/select.html
Roman Elizarov419a6c82017-02-09 18:36:22 +03002814<!--- END -->