blob: 1700dfd20736a8cd0e9305b0af0a879adbe986c1 [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/*
3 * Copyright 2016-2017 JetBrains s.r.o.
4 *
5 * Licensed under the Apache License, Version 2.0 (the "License");
6 * you may not use this file except in compliance with the License.
7 * You may obtain a copy of the License at
8 *
9 * http://www.apache.org/licenses/LICENSE-2.0
10 *
11 * Unless required by applicable law or agreed to in writing, software
12 * distributed under the License is distributed on an "AS IS" BASIS,
13 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 * See the License for the specific language governing permissions and
15 * limitations under the License.
16 */
Roman Elizarovf16fd272017-02-07 11:26:00 +030017
Roman Elizarova5e653f2017-02-13 13:49:55 +030018// This file was automatically generated from coroutines-guide.md by Knit tool. Do not edit.
19package guide.$$1.example$$2
Roman Elizarovf16fd272017-02-07 11:26:00 +030020
Roman Elizarova5e653f2017-02-13 13:49:55 +030021import kotlinx.coroutines.experimental.*
Roman Elizarovf16fd272017-02-07 11:26:00 +030022-->
Roman Elizarove8d79342017-08-29 15:21:21 +030023<!--- KNIT core/kotlinx-coroutines-core/src/test/kotlin/guide/.*\.kt -->
24<!--- TEST_OUT core/kotlinx-coroutines-core/src/test/kotlin/guide/test/GuideTest.kt
Roman Elizarov731f0ad2017-02-22 20:48:45 +030025// This file was automatically generated from coroutines-guide.md by Knit tool. Do not edit.
26package guide.test
27
28import org.junit.Test
29
30class GuideTest {
31-->
Roman Elizarovf16fd272017-02-07 11:26:00 +030032
Roman Elizarov7deefb82017-01-31 10:33:17 +030033# Guide to kotlinx.coroutines by example
34
35This is a short guide on core features of `kotlinx.coroutines` with a series of examples.
36
Roman Elizarov2a638922017-03-04 10:22:43 +030037## Introduction and setup
38
39Kotlin, as a language, provides only minimal low-level APIs in its standard library to enable various other
40libraries to utilize coroutines. Unlike many other languages with similar capabilities, `async` and `await`
41are not keywords in Kotlin and are not even part of its standard library.
42
Robert Hencke497d3432017-04-11 00:14:29 -040043`kotlinx.coroutines` is one such rich library. It contains a number of high-level
Roman Elizarov2a638922017-03-04 10:22:43 +030044coroutine-enabled primitives that this guide covers, including `async` and `await`.
45You need to add a dependency on `kotlinx-coroutines-core` module as explained
46[here](README.md#using-in-your-projects) to use primitives from this guide in your projects.
47
Roman Elizarov1293ccd2017-02-01 18:49:54 +030048## Table of contents
49
Roman Elizarovfa7723e2017-02-06 11:17:51 +030050<!--- TOC -->
51
Roman Elizarov1293ccd2017-02-01 18:49:54 +030052* [Coroutine basics](#coroutine-basics)
53 * [Your first coroutine](#your-first-coroutine)
54 * [Bridging blocking and non-blocking worlds](#bridging-blocking-and-non-blocking-worlds)
55 * [Waiting for a job](#waiting-for-a-job)
56 * [Extract function refactoring](#extract-function-refactoring)
57 * [Coroutines ARE light-weight](#coroutines-are-light-weight)
58 * [Coroutines are like daemon threads](#coroutines-are-like-daemon-threads)
59* [Cancellation and timeouts](#cancellation-and-timeouts)
60 * [Cancelling coroutine execution](#cancelling-coroutine-execution)
61 * [Cancellation is cooperative](#cancellation-is-cooperative)
62 * [Making computation code cancellable](#making-computation-code-cancellable)
63 * [Closing resources with finally](#closing-resources-with-finally)
64 * [Run non-cancellable block](#run-non-cancellable-block)
65 * [Timeout](#timeout)
66* [Composing suspending functions](#composing-suspending-functions)
67 * [Sequential by default](#sequential-by-default)
Roman Elizarov32d95322017-02-09 15:57:31 +030068 * [Concurrent using async](#concurrent-using-async)
69 * [Lazily started async](#lazily-started-async)
70 * [Async-style functions](#async-style-functions)
Roman Elizarov2f6d7c92017-02-03 15:16:07 +030071* [Coroutine context and dispatchers](#coroutine-context-and-dispatchers)
Roman Elizarovfa7723e2017-02-06 11:17:51 +030072 * [Dispatchers and threads](#dispatchers-and-threads)
Roman Elizarov2f6d7c92017-02-03 15:16:07 +030073 * [Unconfined vs confined dispatcher](#unconfined-vs-confined-dispatcher)
74 * [Debugging coroutines and threads](#debugging-coroutines-and-threads)
75 * [Jumping between threads](#jumping-between-threads)
76 * [Job in the context](#job-in-the-context)
77 * [Children of a coroutine](#children-of-a-coroutine)
78 * [Combining contexts](#combining-contexts)
Roman Elizarov8b38fa22017-09-27 17:44:31 +030079 * [Parental responsibilities](#parental-responsibilities)
Roman Elizarov2f6d7c92017-02-03 15:16:07 +030080 * [Naming coroutines for debugging](#naming-coroutines-for-debugging)
Roman Elizarov2fd7cb32017-02-11 23:18:59 +030081 * [Cancellation via explicit job](#cancellation-via-explicit-job)
Roman Elizarovb7721cf2017-02-03 19:23:08 +030082* [Channels](#channels)
83 * [Channel basics](#channel-basics)
84 * [Closing and iteration over channels](#closing-and-iteration-over-channels)
85 * [Building channel producers](#building-channel-producers)
86 * [Pipelines](#pipelines)
87 * [Prime numbers with pipeline](#prime-numbers-with-pipeline)
88 * [Fan-out](#fan-out)
89 * [Fan-in](#fan-in)
90 * [Buffered channels](#buffered-channels)
Roman Elizarovb0517ba2017-02-27 14:03:14 +030091 * [Channels are fair](#channels-are-fair)
Roman Elizarovf5bc0472017-02-22 11:38:13 +030092* [Shared mutable state and concurrency](#shared-mutable-state-and-concurrency)
93 * [The problem](#the-problem)
Roman Elizarov1e459602017-02-27 11:05:17 +030094 * [Volatiles are of no help](#volatiles-are-of-no-help)
Roman Elizarovf5bc0472017-02-22 11:38:13 +030095 * [Thread-safe data structures](#thread-safe-data-structures)
Roman Elizarov1e459602017-02-27 11:05:17 +030096 * [Thread confinement fine-grained](#thread-confinement-fine-grained)
97 * [Thread confinement coarse-grained](#thread-confinement-coarse-grained)
Roman Elizarovf5bc0472017-02-22 11:38:13 +030098 * [Mutual exclusion](#mutual-exclusion)
99 * [Actors](#actors)
Roman Elizarovd4dcbe22017-02-22 09:57:46 +0300100* [Select expression](#select-expression)
101 * [Selecting from channels](#selecting-from-channels)
102 * [Selecting on close](#selecting-on-close)
103 * [Selecting to send](#selecting-to-send)
104 * [Selecting deferred values](#selecting-deferred-values)
105 * [Switch over a channel of deferred values](#switch-over-a-channel-of-deferred-values)
Roman Elizarov8db17332017-03-09 12:40:45 +0300106* [Further reading](#further-reading)
Roman Elizarovfa7723e2017-02-06 11:17:51 +0300107
Roman Elizarova5e653f2017-02-13 13:49:55 +0300108<!--- END_TOC -->
Roman Elizarov1293ccd2017-02-01 18:49:54 +0300109
110## Coroutine basics
111
112This section covers basic coroutine concepts.
113
114### Your first coroutine
Roman Elizarov7deefb82017-01-31 10:33:17 +0300115
116Run the following code:
117
118```kotlin
119fun main(args: Array<String>) {
Roman Elizarov66f018c2017-09-29 21:39:03 +0300120 launch { // launch new coroutine
Roman Elizarov7deefb82017-01-31 10:33:17 +0300121 delay(1000L) // non-blocking delay for 1 second (default time unit is ms)
122 println("World!") // print after delay
123 }
124 println("Hello,") // main function continues while coroutine is delayed
125 Thread.sleep(2000L) // block main thread for 2 seconds to keep JVM alive
126}
127```
128
Roman Elizarove8d79342017-08-29 15:21:21 +0300129> You can get full code [here](core/kotlinx-coroutines-core/src/test/kotlin/guide/example-basic-01.kt)
Roman Elizarov7deefb82017-01-31 10:33:17 +0300130
131Run this code:
132
Roman Elizarov731f0ad2017-02-22 20:48:45 +0300133```text
Roman Elizarov7deefb82017-01-31 10:33:17 +0300134Hello,
135World!
136```
137
Roman Elizarov731f0ad2017-02-22 20:48:45 +0300138<!--- TEST -->
139
Roman Elizarov419a6c82017-02-09 18:36:22 +0300140Essentially, coroutines are light-weight threads.
141They are launched with [launch] _coroutine builder_.
142You can achieve the same result replacing
Roman Elizarov66f018c2017-09-29 21:39:03 +0300143`launch { ... }` with `thread { ... }` and `delay(...)` with `Thread.sleep(...)`. Try it.
Roman Elizarov7deefb82017-01-31 10:33:17 +0300144
Roman Elizarov66f018c2017-09-29 21:39:03 +0300145If you start by replacing `launch` by `thread`, the compiler produces the following error:
Roman Elizarov7deefb82017-01-31 10:33:17 +0300146
147```
148Error: Kotlin: Suspend functions are only allowed to be called from a coroutine or another suspend function
149```
150
Roman Elizarov419a6c82017-02-09 18:36:22 +0300151That is because [delay] is a special _suspending function_ that does not block a thread, but _suspends_
Roman Elizarov7deefb82017-01-31 10:33:17 +0300152coroutine and it can be only used from a coroutine.
153
Roman Elizarov1293ccd2017-02-01 18:49:54 +0300154### Bridging blocking and non-blocking worlds
Roman Elizarov7deefb82017-01-31 10:33:17 +0300155
156The first example mixes _non-blocking_ `delay(...)` and _blocking_ `Thread.sleep(...)` in the same
157code of `main` function. It is easy to get lost. Let's cleanly separate blocking and non-blocking
Roman Elizarov419a6c82017-02-09 18:36:22 +0300158worlds by using [runBlocking]:
Roman Elizarov7deefb82017-01-31 10:33:17 +0300159
160```kotlin
161fun main(args: Array<String>) = runBlocking<Unit> { // start main coroutine
Roman Elizarov66f018c2017-09-29 21:39:03 +0300162 launch { // launch new coroutine
Roman Elizarov7deefb82017-01-31 10:33:17 +0300163 delay(1000L)
164 println("World!")
165 }
166 println("Hello,") // main coroutine continues while child is delayed
167 delay(2000L) // non-blocking delay for 2 seconds to keep JVM alive
168}
169```
170
Roman Elizarove8d79342017-08-29 15:21:21 +0300171> You can get full code [here](core/kotlinx-coroutines-core/src/test/kotlin/guide/example-basic-02.kt)
Roman Elizarov7deefb82017-01-31 10:33:17 +0300172
Roman Elizarov731f0ad2017-02-22 20:48:45 +0300173<!--- TEST
174Hello,
175World!
176-->
177
Roman Elizarov419a6c82017-02-09 18:36:22 +0300178The result is the same, but this code uses only non-blocking [delay].
Roman Elizarov7deefb82017-01-31 10:33:17 +0300179
180`runBlocking { ... }` works as an adaptor that is used here to start the top-level main coroutine.
181The regular code outside of `runBlocking` _blocks_, until the coroutine inside `runBlocking` is active.
182
183This is also a way to write unit-tests for suspending functions:
184
185```kotlin
186class MyTest {
187 @Test
188 fun testMySuspendingFunction() = runBlocking<Unit> {
189 // here we can use suspending functions using any assertion style that we like
190 }
191}
192```
Roman Elizarovb3d55a52017-02-03 12:47:21 +0300193
194<!--- CLEAR -->
Roman Elizarov7deefb82017-01-31 10:33:17 +0300195
Roman Elizarov1293ccd2017-02-01 18:49:54 +0300196### Waiting for a job
Roman Elizarov7deefb82017-01-31 10:33:17 +0300197
Roman Elizarov1293ccd2017-02-01 18:49:54 +0300198Delaying for a time while another coroutine is working is not a good approach. Let's explicitly
Roman Elizarov419a6c82017-02-09 18:36:22 +0300199wait (in a non-blocking way) until the background [Job] that we have launched is complete:
Roman Elizarov7deefb82017-01-31 10:33:17 +0300200
201```kotlin
202fun main(args: Array<String>) = runBlocking<Unit> {
Roman Elizarov66f018c2017-09-29 21:39:03 +0300203 val job = launch { // launch new coroutine and keep a reference to its Job
Roman Elizarov7deefb82017-01-31 10:33:17 +0300204 delay(1000L)
205 println("World!")
206 }
207 println("Hello,")
208 job.join() // wait until child coroutine completes
209}
210```
211
Roman Elizarove8d79342017-08-29 15:21:21 +0300212> You can get full code [here](core/kotlinx-coroutines-core/src/test/kotlin/guide/example-basic-03.kt)
Roman Elizarov7deefb82017-01-31 10:33:17 +0300213
Roman Elizarov731f0ad2017-02-22 20:48:45 +0300214<!--- TEST
215Hello,
216World!
217-->
218
Roman Elizarov7deefb82017-01-31 10:33:17 +0300219Now 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 +0300220the background job in any way. Much better.
Roman Elizarov7deefb82017-01-31 10:33:17 +0300221
Roman Elizarov1293ccd2017-02-01 18:49:54 +0300222### Extract function refactoring
Roman Elizarov7deefb82017-01-31 10:33:17 +0300223
Roman Elizarov66f018c2017-09-29 21:39:03 +0300224Let's extract the block of code inside `launch { ... }` into a separate function. When you
Roman Elizarov7deefb82017-01-31 10:33:17 +0300225perform "Extract function" refactoring on this code you get a new function with `suspend` modifier.
226That is your first _suspending function_. Suspending functions can be used inside coroutines
227just like regular functions, but their additional feature is that they can, in turn,
228use other suspending functions, like `delay` in this example, to _suspend_ execution of a coroutine.
229
230```kotlin
231fun main(args: Array<String>) = runBlocking<Unit> {
Roman Elizarov66f018c2017-09-29 21:39:03 +0300232 val job = launch { doWorld() }
Roman Elizarov7deefb82017-01-31 10:33:17 +0300233 println("Hello,")
234 job.join()
235}
236
237// this is your first suspending function
238suspend fun doWorld() {
239 delay(1000L)
240 println("World!")
241}
242```
243
Roman Elizarove8d79342017-08-29 15:21:21 +0300244> You can get full code [here](core/kotlinx-coroutines-core/src/test/kotlin/guide/example-basic-04.kt)
Roman Elizarov7deefb82017-01-31 10:33:17 +0300245
Roman Elizarov731f0ad2017-02-22 20:48:45 +0300246<!--- TEST
247Hello,
248World!
249-->
250
Roman Elizarov1293ccd2017-02-01 18:49:54 +0300251### Coroutines ARE light-weight
Roman Elizarov7deefb82017-01-31 10:33:17 +0300252
253Run the following code:
254
255```kotlin
256fun main(args: Array<String>) = runBlocking<Unit> {
Roman Elizarov66f018c2017-09-29 21:39:03 +0300257 val jobs = List(100_000) { // launch a lot of coroutines and list their jobs
258 launch {
Roman Elizarov7deefb82017-01-31 10:33:17 +0300259 delay(1000L)
260 print(".")
261 }
262 }
263 jobs.forEach { it.join() } // wait for all jobs to complete
264}
265```
266
Roman Elizarove8d79342017-08-29 15:21:21 +0300267> You can get full code [here](core/kotlinx-coroutines-core/src/test/kotlin/guide/example-basic-05.kt)
Roman Elizarov7deefb82017-01-31 10:33:17 +0300268
Roman Elizarov731f0ad2017-02-22 20:48:45 +0300269<!--- TEST lines.size == 1 && lines[0] == ".".repeat(100_000) -->
270
Roman Elizarov66f018c2017-09-29 21:39:03 +0300271It launches 100K coroutines and, after a second, each coroutine prints a dot.
Roman Elizarov7deefb82017-01-31 10:33:17 +0300272Now, try that with threads. What would happen? (Most likely your code will produce some sort of out-of-memory error)
273
Roman Elizarov1293ccd2017-02-01 18:49:54 +0300274### Coroutines are like daemon threads
Roman Elizarov7deefb82017-01-31 10:33:17 +0300275
276The following code launches a long-running coroutine that prints "I'm sleeping" twice a second and then
Roman Elizarov1293ccd2017-02-01 18:49:54 +0300277returns from the main function after some delay:
Roman Elizarov7deefb82017-01-31 10:33:17 +0300278
279```kotlin
280fun main(args: Array<String>) = runBlocking<Unit> {
Roman Elizarov66f018c2017-09-29 21:39:03 +0300281 launch {
Roman Elizarov7deefb82017-01-31 10:33:17 +0300282 repeat(1000) { i ->
283 println("I'm sleeping $i ...")
284 delay(500L)
285 }
286 }
287 delay(1300L) // just quit after delay
288}
289```
290
Roman Elizarove8d79342017-08-29 15:21:21 +0300291> You can get full code [here](core/kotlinx-coroutines-core/src/test/kotlin/guide/example-basic-06.kt)
Roman Elizarov7deefb82017-01-31 10:33:17 +0300292
293You can run and see that it prints three lines and terminates:
294
Roman Elizarov731f0ad2017-02-22 20:48:45 +0300295```text
Roman Elizarov7deefb82017-01-31 10:33:17 +0300296I'm sleeping 0 ...
297I'm sleeping 1 ...
298I'm sleeping 2 ...
299```
300
Roman Elizarov731f0ad2017-02-22 20:48:45 +0300301<!--- TEST -->
302
Roman Elizarov7deefb82017-01-31 10:33:17 +0300303Active coroutines do not keep the process alive. They are like daemon threads.
304
Roman Elizarov1293ccd2017-02-01 18:49:54 +0300305## Cancellation and timeouts
306
307This section covers coroutine cancellation and timeouts.
308
309### Cancelling coroutine execution
Roman Elizarov7deefb82017-01-31 10:33:17 +0300310
311In small application the return from "main" method might sound like a good idea to get all coroutines
312implicitly terminated. In a larger, long-running application, you need finer-grained control.
Roman Elizarov419a6c82017-02-09 18:36:22 +0300313The [launch] function returns a [Job] that can be used to cancel running coroutine:
Roman Elizarov7deefb82017-01-31 10:33:17 +0300314
315```kotlin
316fun main(args: Array<String>) = runBlocking<Unit> {
Roman Elizarov66f018c2017-09-29 21:39:03 +0300317 val job = launch {
Roman Elizarov7deefb82017-01-31 10:33:17 +0300318 repeat(1000) { i ->
319 println("I'm sleeping $i ...")
320 delay(500L)
321 }
322 }
323 delay(1300L) // delay a bit
Roman Elizarov1293ccd2017-02-01 18:49:54 +0300324 println("main: I'm tired of waiting!")
Roman Elizarov7deefb82017-01-31 10:33:17 +0300325 job.cancel() // cancels the job
Roman Elizarov8b38fa22017-09-27 17:44:31 +0300326 job.join() // waits for job's completion
Roman Elizarov1293ccd2017-02-01 18:49:54 +0300327 println("main: Now I can quit.")
Roman Elizarov7deefb82017-01-31 10:33:17 +0300328}
329```
330
Roman Elizarove8d79342017-08-29 15:21:21 +0300331> You can get full code [here](core/kotlinx-coroutines-core/src/test/kotlin/guide/example-cancel-01.kt)
Roman Elizarov7deefb82017-01-31 10:33:17 +0300332
Roman Elizarov1293ccd2017-02-01 18:49:54 +0300333It produces the following output:
334
Roman Elizarov731f0ad2017-02-22 20:48:45 +0300335```text
Roman Elizarov1293ccd2017-02-01 18:49:54 +0300336I'm sleeping 0 ...
337I'm sleeping 1 ...
338I'm sleeping 2 ...
339main: I'm tired of waiting!
340main: Now I can quit.
341```
342
Roman Elizarov731f0ad2017-02-22 20:48:45 +0300343<!--- TEST -->
344
Roman Elizarov1293ccd2017-02-01 18:49:54 +0300345As 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 +0300346There is also a [Job] extension function [cancelAndJoin]
347that combines [cancel][Job.cancel] and [join][Job.join] invocations.
Roman Elizarov1293ccd2017-02-01 18:49:54 +0300348
349### Cancellation is cooperative
Roman Elizarov7deefb82017-01-31 10:33:17 +0300350
Tair Rzayevaf734622017-02-01 22:30:16 +0200351Coroutine cancellation is _cooperative_. A coroutine code has to cooperate to be cancellable.
Roman Elizarov7deefb82017-01-31 10:33:17 +0300352All the suspending functions in `kotlinx.coroutines` are _cancellable_. They check for cancellation of
Roman Elizarov419a6c82017-02-09 18:36:22 +0300353coroutine and throw [CancellationException] when cancelled. However, if a coroutine is working in
Roman Elizarov7deefb82017-01-31 10:33:17 +0300354a computation and does not check for cancellation, then it cannot be cancelled, like the following
355example shows:
356
357```kotlin
358fun main(args: Array<String>) = runBlocking<Unit> {
Roman Elizarov24cd6542017-08-03 21:20:04 -0700359 val startTime = System.currentTimeMillis()
Roman Elizarov66f018c2017-09-29 21:39:03 +0300360 val job = launch {
Roman Elizarov24cd6542017-08-03 21:20:04 -0700361 var nextPrintTime = startTime
Roman Elizarov7deefb82017-01-31 10:33:17 +0300362 var i = 0
Roman Elizarov8b38fa22017-09-27 17:44:31 +0300363 while (i < 5) { // computation loop, just wastes CPU
Roman Elizarov24cd6542017-08-03 21:20:04 -0700364 // print a message twice a second
365 if (System.currentTimeMillis() >= nextPrintTime) {
Roman Elizarov7deefb82017-01-31 10:33:17 +0300366 println("I'm sleeping ${i++} ...")
Roman Elizarov35d2c342017-07-20 14:54:39 +0300367 nextPrintTime += 500L
Roman Elizarov7deefb82017-01-31 10:33:17 +0300368 }
369 }
370 }
371 delay(1300L) // delay a bit
Roman Elizarov1293ccd2017-02-01 18:49:54 +0300372 println("main: I'm tired of waiting!")
Roman Elizarov8b38fa22017-09-27 17:44:31 +0300373 job.cancelAndJoin() // cancels the job and waits for its completion
Roman Elizarov1293ccd2017-02-01 18:49:54 +0300374 println("main: Now I can quit.")
Roman Elizarov7deefb82017-01-31 10:33:17 +0300375}
376```
377
Roman Elizarove8d79342017-08-29 15:21:21 +0300378> You can get full code [here](core/kotlinx-coroutines-core/src/test/kotlin/guide/example-cancel-02.kt)
Roman Elizarov7deefb82017-01-31 10:33:17 +0300379
Roman Elizarov8b38fa22017-09-27 17:44:31 +0300380Run it to see that it continues to print "I'm sleeping" even after cancellation
381until the job completes by itself after five iterations.
Roman Elizarov7deefb82017-01-31 10:33:17 +0300382
Roman Elizarov731f0ad2017-02-22 20:48:45 +0300383<!--- TEST
384I'm sleeping 0 ...
385I'm sleeping 1 ...
386I'm sleeping 2 ...
387main: I'm tired of waiting!
388I'm sleeping 3 ...
389I'm sleeping 4 ...
Roman Elizarov731f0ad2017-02-22 20:48:45 +0300390main: Now I can quit.
391-->
392
Roman Elizarov1293ccd2017-02-01 18:49:54 +0300393### Making computation code cancellable
Roman Elizarov7deefb82017-01-31 10:33:17 +0300394
395There are two approaches to making computation code cancellable. The first one is to periodically
Roman Elizarov66f018c2017-09-29 21:39:03 +0300396invoke 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 +0300397The other one is to explicitly check the cancellation status. Let us try the later approach.
Roman Elizarov7deefb82017-01-31 10:33:17 +0300398
Roman Elizarov8b38fa22017-09-27 17:44:31 +0300399Replace `while (i < 5)` in the previous example with `while (isActive)` and rerun it.
Roman Elizarov7deefb82017-01-31 10:33:17 +0300400
Roman Elizarovb3d55a52017-02-03 12:47:21 +0300401```kotlin
402fun main(args: Array<String>) = runBlocking<Unit> {
Roman Elizarov24cd6542017-08-03 21:20:04 -0700403 val startTime = System.currentTimeMillis()
Roman Elizarov66f018c2017-09-29 21:39:03 +0300404 val job = launch {
Roman Elizarov24cd6542017-08-03 21:20:04 -0700405 var nextPrintTime = startTime
Roman Elizarovb3d55a52017-02-03 12:47:21 +0300406 var i = 0
407 while (isActive) { // cancellable computation loop
Roman Elizarov24cd6542017-08-03 21:20:04 -0700408 // print a message twice a second
409 if (System.currentTimeMillis() >= nextPrintTime) {
Roman Elizarovb3d55a52017-02-03 12:47:21 +0300410 println("I'm sleeping ${i++} ...")
Roman Elizarov24cd6542017-08-03 21:20:04 -0700411 nextPrintTime += 500L
Roman Elizarovb3d55a52017-02-03 12:47:21 +0300412 }
413 }
414 }
415 delay(1300L) // delay a bit
416 println("main: I'm tired of waiting!")
Roman Elizarov8b38fa22017-09-27 17:44:31 +0300417 job.cancelAndJoin() // cancels the job and waits for its completion
Roman Elizarovb3d55a52017-02-03 12:47:21 +0300418 println("main: Now I can quit.")
419}
420```
421
Roman Elizarove8d79342017-08-29 15:21:21 +0300422> You can get full code [here](core/kotlinx-coroutines-core/src/test/kotlin/guide/example-cancel-03.kt)
Roman Elizarov7deefb82017-01-31 10:33:17 +0300423
Roman Elizarov8b38fa22017-09-27 17:44:31 +0300424As 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 +0300425the code of coroutines via [CoroutineScope] object.
Roman Elizarov7deefb82017-01-31 10:33:17 +0300426
Roman Elizarov731f0ad2017-02-22 20:48:45 +0300427<!--- TEST
428I'm sleeping 0 ...
429I'm sleeping 1 ...
430I'm sleeping 2 ...
431main: I'm tired of waiting!
432main: Now I can quit.
433-->
434
Roman Elizarov1293ccd2017-02-01 18:49:54 +0300435### Closing resources with finally
436
Roman Elizarov419a6c82017-02-09 18:36:22 +0300437Cancellable suspending functions throw [CancellationException] on cancellation which can be handled in
Roman Elizarov66f018c2017-09-29 21:39:03 +0300438all the usual way. For example, `try {...} finally {...}` expression and Kotlin `use` function execute their
Roman Elizarov1293ccd2017-02-01 18:49:54 +0300439finalization actions normally when coroutine is cancelled:
440
441```kotlin
442fun main(args: Array<String>) = runBlocking<Unit> {
Roman Elizarov66f018c2017-09-29 21:39:03 +0300443 val job = launch {
Roman Elizarov1293ccd2017-02-01 18:49:54 +0300444 try {
445 repeat(1000) { i ->
446 println("I'm sleeping $i ...")
447 delay(500L)
448 }
449 } finally {
450 println("I'm running finally")
451 }
452 }
453 delay(1300L) // delay a bit
454 println("main: I'm tired of waiting!")
Roman Elizarov8b38fa22017-09-27 17:44:31 +0300455 job.cancelAndJoin() // cancels the job and waits for its completion
Roman Elizarov1293ccd2017-02-01 18:49:54 +0300456 println("main: Now I can quit.")
457}
458```
459
Roman Elizarove8d79342017-08-29 15:21:21 +0300460> You can get full code [here](core/kotlinx-coroutines-core/src/test/kotlin/guide/example-cancel-04.kt)
Roman Elizarov1293ccd2017-02-01 18:49:54 +0300461
Roman Elizarov88396732017-09-27 21:30:47 +0300462Both [join][Job.join] and [cancelAndJoin] wait for all the finalization actions to complete,
463so the example above produces the following output:
Roman Elizarov1293ccd2017-02-01 18:49:54 +0300464
Roman Elizarov731f0ad2017-02-22 20:48:45 +0300465```text
Roman Elizarov1293ccd2017-02-01 18:49:54 +0300466I'm sleeping 0 ...
467I'm sleeping 1 ...
468I'm sleeping 2 ...
469main: I'm tired of waiting!
470I'm running finally
471main: Now I can quit.
472```
473
Roman Elizarov731f0ad2017-02-22 20:48:45 +0300474<!--- TEST -->
475
Roman Elizarov1293ccd2017-02-01 18:49:54 +0300476### Run non-cancellable block
477
478Any attempt to use a suspending function in the `finally` block of the previous example will cause
Roman Elizarov419a6c82017-02-09 18:36:22 +0300479[CancellationException], because the coroutine running this code is cancelled. Usually, this is not a
Roman Elizarov1293ccd2017-02-01 18:49:54 +0300480problem, since all well-behaving closing operations (closing a file, cancelling a job, or closing any kind of a
481communication channel) are usually non-blocking and do not involve any suspending functions. However, in the
482rare case when you need to suspend in the cancelled coroutine you can wrap the corresponding code in
Roman Elizarov419a6c82017-02-09 18:36:22 +0300483`run(NonCancellable) {...}` using [run] function and [NonCancellable] context as the following example shows:
Roman Elizarov1293ccd2017-02-01 18:49:54 +0300484
485```kotlin
486fun main(args: Array<String>) = runBlocking<Unit> {
Roman Elizarov66f018c2017-09-29 21:39:03 +0300487 val job = launch {
Roman Elizarov1293ccd2017-02-01 18:49:54 +0300488 try {
489 repeat(1000) { i ->
490 println("I'm sleeping $i ...")
491 delay(500L)
492 }
493 } finally {
494 run(NonCancellable) {
495 println("I'm running finally")
496 delay(1000L)
497 println("And I've just delayed for 1 sec because I'm non-cancellable")
498 }
499 }
500 }
501 delay(1300L) // delay a bit
502 println("main: I'm tired of waiting!")
Roman Elizarov8b38fa22017-09-27 17:44:31 +0300503 job.cancelAndJoin() // cancels the job and waits for its completion
Roman Elizarov1293ccd2017-02-01 18:49:54 +0300504 println("main: Now I can quit.")
505}
506```
507
Roman Elizarove8d79342017-08-29 15:21:21 +0300508> You can get full code [here](core/kotlinx-coroutines-core/src/test/kotlin/guide/example-cancel-05.kt)
Roman Elizarov1293ccd2017-02-01 18:49:54 +0300509
Roman Elizarov731f0ad2017-02-22 20:48:45 +0300510<!--- TEST
511I'm sleeping 0 ...
512I'm sleeping 1 ...
513I'm sleeping 2 ...
514main: I'm tired of waiting!
515I'm running finally
516And I've just delayed for 1 sec because I'm non-cancellable
517main: Now I can quit.
518-->
519
Roman Elizarov1293ccd2017-02-01 18:49:54 +0300520### Timeout
521
522The most obvious reason to cancel coroutine execution in practice,
523is because its execution time has exceeded some timeout.
Roman Elizarov419a6c82017-02-09 18:36:22 +0300524While you can manually track the reference to the corresponding [Job] and launch a separate coroutine to cancel
525the tracked one after delay, there is a ready to use [withTimeout] function that does it.
Roman Elizarov1293ccd2017-02-01 18:49:54 +0300526Look at the following example:
527
528```kotlin
529fun main(args: Array<String>) = runBlocking<Unit> {
530 withTimeout(1300L) {
531 repeat(1000) { i ->
532 println("I'm sleeping $i ...")
533 delay(500L)
534 }
535 }
536}
537```
538
Roman Elizarove8d79342017-08-29 15:21:21 +0300539> You can get full code [here](core/kotlinx-coroutines-core/src/test/kotlin/guide/example-cancel-06.kt)
Roman Elizarov1293ccd2017-02-01 18:49:54 +0300540
541It produces the following output:
542
Roman Elizarov731f0ad2017-02-22 20:48:45 +0300543```text
Roman Elizarov1293ccd2017-02-01 18:49:54 +0300544I'm sleeping 0 ...
545I'm sleeping 1 ...
546I'm sleeping 2 ...
Roman Elizarov63f6ea22017-09-06 18:42:34 +0300547Exception in thread "main" kotlinx.coroutines.experimental.TimeoutCancellationException: Timed out waiting for 1300 MILLISECONDS
Roman Elizarov1293ccd2017-02-01 18:49:54 +0300548```
549
Roman Elizarov731f0ad2017-02-22 20:48:45 +0300550<!--- TEST STARTS_WITH -->
551
Roman Elizarov63f6ea22017-09-06 18:42:34 +0300552The `TimeoutCancellationException` that is thrown by [withTimeout] is a subclass of [CancellationException].
Roman Elizarovca9d5be2017-04-20 19:23:18 +0300553We have not seen its stack trace printed on the console before. That is because
Roman Elizarov7c864d82017-02-27 10:17:50 +0300554inside a cancelled coroutine `CancellationException` is considered to be a normal reason for coroutine completion.
Roman Elizarov1293ccd2017-02-01 18:49:54 +0300555However, in this example we have used `withTimeout` right inside the `main` function.
556
557Because cancellation is just an exception, all the resources will be closed in a usual way.
Roman Elizarov63f6ea22017-09-06 18:42:34 +0300558You can wrap the code with timeout in `try {...} catch (e: TimeoutCancellationException) {...}` block if
559you need to do some additional action specifically on any kind of timeout or use [withTimeoutOrNull] function
Roman Elizarov8b38fa22017-09-27 17:44:31 +0300560that is similar to [withTimeout], but returns `null` on timeout instead of throwing an exception:
561
562```kotlin
563fun main(args: Array<String>) = runBlocking<Unit> {
564 val result = withTimeoutOrNull(1300L) {
565 repeat(1000) { i ->
566 println("I'm sleeping $i ...")
567 delay(500L)
568 }
569 "Done" // will get cancelled before it produces this result
570 }
571 println("Result is $result")
572}
573```
574
575> You can get full code [here](core/kotlinx-coroutines-core/src/test/kotlin/guide/example-cancel-07.kt)
576
577There is no longer an exception when running this code:
578
579```text
580I'm sleeping 0 ...
581I'm sleeping 1 ...
582I'm sleeping 2 ...
583Result is null
584```
585
586<!--- TEST -->
Roman Elizarov1293ccd2017-02-01 18:49:54 +0300587
588## Composing suspending functions
589
590This section covers various approaches to composition of suspending functions.
591
592### Sequential by default
593
594Assume that we have two suspending functions defined elsewhere that do something useful like some kind of
Roman Elizarovb7721cf2017-02-03 19:23:08 +0300595remote service call or computation. We just pretend they are useful, but actually each one just
596delays for a second for the purpose of this example:
Roman Elizarov1293ccd2017-02-01 18:49:54 +0300597
Roman Elizarovfa7723e2017-02-06 11:17:51 +0300598<!--- INCLUDE .*/example-compose-([0-9]+).kt
599import kotlin.system.measureTimeMillis
600-->
601
Roman Elizarov1293ccd2017-02-01 18:49:54 +0300602```kotlin
603suspend fun doSomethingUsefulOne(): Int {
604 delay(1000L) // pretend we are doing something useful here
605 return 13
606}
607
608suspend fun doSomethingUsefulTwo(): Int {
609 delay(1000L) // pretend we are doing something useful here, too
610 return 29
611}
612```
613
Roman Elizarovfa7723e2017-02-06 11:17:51 +0300614<!--- INCLUDE .*/example-compose-([0-9]+).kt -->
615
Roman Elizarov1293ccd2017-02-01 18:49:54 +0300616What do we do if need to invoke them _sequentially_ -- first `doSomethingUsefulOne` _and then_
617`doSomethingUsefulTwo` and compute the sum of their results?
618In practise we do this if we use the results of the first function to make a decision on whether we need
619to invoke the second one or to decide on how to invoke it.
620
621We just use a normal sequential invocation, because the code in the coroutine, just like in the regular
Roman Elizarov32d95322017-02-09 15:57:31 +0300622code, is _sequential_ by default. The following example demonstrates it by measuring the total
Roman Elizarov1293ccd2017-02-01 18:49:54 +0300623time it takes to execute both suspending functions:
624
625```kotlin
626fun main(args: Array<String>) = runBlocking<Unit> {
627 val time = measureTimeMillis {
628 val one = doSomethingUsefulOne()
629 val two = doSomethingUsefulTwo()
630 println("The answer is ${one + two}")
631 }
632 println("Completed in $time ms")
633}
634```
635
Roman Elizarove8d79342017-08-29 15:21:21 +0300636> You can get full code [here](core/kotlinx-coroutines-core/src/test/kotlin/guide/example-compose-01.kt)
Roman Elizarov1293ccd2017-02-01 18:49:54 +0300637
638It produces something like this:
639
Roman Elizarov731f0ad2017-02-22 20:48:45 +0300640```text
Roman Elizarov1293ccd2017-02-01 18:49:54 +0300641The answer is 42
642Completed in 2017 ms
643```
644
Roman Elizarov35d2c342017-07-20 14:54:39 +0300645<!--- TEST ARBITRARY_TIME -->
Roman Elizarov731f0ad2017-02-22 20:48:45 +0300646
Roman Elizarov32d95322017-02-09 15:57:31 +0300647### Concurrent using async
Roman Elizarov1293ccd2017-02-01 18:49:54 +0300648
649What if there are no dependencies between invocation of `doSomethingUsefulOne` and `doSomethingUsefulTwo` and
Roman Elizarov419a6c82017-02-09 18:36:22 +0300650we want to get the answer faster, by doing both _concurrently_? This is where [async] comes to help.
Roman Elizarov1293ccd2017-02-01 18:49:54 +0300651
Roman Elizarov419a6c82017-02-09 18:36:22 +0300652Conceptually, [async] is just like [launch]. It starts a separate coroutine which is a light-weight thread
653that works concurrently with all the other coroutines. The difference is that `launch` returns a [Job] and
654does not carry any resulting value, while `async` returns a [Deferred] -- a light-weight non-blocking future
Roman Elizarov32d95322017-02-09 15:57:31 +0300655that 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 +0300656but `Deferred` is also a `Job`, so you can cancel it if needed.
657
658```kotlin
659fun main(args: Array<String>) = runBlocking<Unit> {
660 val time = measureTimeMillis {
Roman Elizarov66f018c2017-09-29 21:39:03 +0300661 val one = async { doSomethingUsefulOne() }
662 val two = async { doSomethingUsefulTwo() }
Roman Elizarov1293ccd2017-02-01 18:49:54 +0300663 println("The answer is ${one.await() + two.await()}")
664 }
665 println("Completed in $time ms")
666}
667```
668
Roman Elizarove8d79342017-08-29 15:21:21 +0300669> You can get full code [here](core/kotlinx-coroutines-core/src/test/kotlin/guide/example-compose-02.kt)
Roman Elizarov1293ccd2017-02-01 18:49:54 +0300670
671It produces something like this:
672
Roman Elizarov731f0ad2017-02-22 20:48:45 +0300673```text
Roman Elizarov1293ccd2017-02-01 18:49:54 +0300674The answer is 42
675Completed in 1017 ms
676```
677
Roman Elizarov35d2c342017-07-20 14:54:39 +0300678<!--- TEST ARBITRARY_TIME -->
Roman Elizarov731f0ad2017-02-22 20:48:45 +0300679
Roman Elizarov1293ccd2017-02-01 18:49:54 +0300680This is twice as fast, because we have concurrent execution of two coroutines.
681Note, that concurrency with coroutines is always explicit.
682
Roman Elizarov32d95322017-02-09 15:57:31 +0300683### Lazily started async
Roman Elizarov1293ccd2017-02-01 18:49:54 +0300684
Roman Elizarov66f018c2017-09-29 21:39:03 +0300685There is a laziness option to [async] using an optional `start` parameter with a value of [CoroutineStart.LAZY].
Roman Elizarov419a6c82017-02-09 18:36:22 +0300686It starts coroutine only when its result is needed by some
687[await][Deferred.await] or if a [start][Job.start] function
Roman Elizarov32d95322017-02-09 15:57:31 +0300688is invoked. Run the following example that differs from the previous one only by this option:
Roman Elizarov1293ccd2017-02-01 18:49:54 +0300689
690```kotlin
691fun main(args: Array<String>) = runBlocking<Unit> {
692 val time = measureTimeMillis {
Roman Elizarov66f018c2017-09-29 21:39:03 +0300693 val one = async(start = CoroutineStart.LAZY) { doSomethingUsefulOne() }
694 val two = async(start = CoroutineStart.LAZY) { doSomethingUsefulTwo() }
Roman Elizarov1293ccd2017-02-01 18:49:54 +0300695 println("The answer is ${one.await() + two.await()}")
696 }
697 println("Completed in $time ms")
698}
699```
700
Roman Elizarove8d79342017-08-29 15:21:21 +0300701> You can get full code [here](core/kotlinx-coroutines-core/src/test/kotlin/guide/example-compose-03.kt)
Roman Elizarov1293ccd2017-02-01 18:49:54 +0300702
703It produces something like this:
704
Roman Elizarov731f0ad2017-02-22 20:48:45 +0300705```text
Roman Elizarov1293ccd2017-02-01 18:49:54 +0300706The answer is 42
707Completed in 2017 ms
708```
709
Roman Elizarov35d2c342017-07-20 14:54:39 +0300710<!--- TEST ARBITRARY_TIME -->
Roman Elizarov731f0ad2017-02-22 20:48:45 +0300711
Roman Elizarov32d95322017-02-09 15:57:31 +0300712So, we are back to sequential execution, because we _first_ start and await for `one`, _and then_ start and await
713for `two`. It is not the intended use-case for laziness. It is designed as a replacement for
714the standard `lazy` function in cases when computation of the value involves suspending functions.
715
716### Async-style functions
717
718We can define async-style functions that invoke `doSomethingUsefulOne` and `doSomethingUsefulTwo`
Roman Elizarov419a6c82017-02-09 18:36:22 +0300719_asynchronously_ using [async] coroutine builder. It is a good style to name such functions with
Roman Elizarov32d95322017-02-09 15:57:31 +0300720either "async" prefix of "Async" suffix to highlight the fact that they only start asynchronous
721computation and one needs to use the resulting deferred value to get the result.
722
723```kotlin
724// The result type of asyncSomethingUsefulOne is Deferred<Int>
Roman Elizarov66f018c2017-09-29 21:39:03 +0300725fun asyncSomethingUsefulOne() = async {
Roman Elizarov32d95322017-02-09 15:57:31 +0300726 doSomethingUsefulOne()
727}
728
729// The result type of asyncSomethingUsefulTwo is Deferred<Int>
Roman Elizarov66f018c2017-09-29 21:39:03 +0300730fun asyncSomethingUsefulTwo() = async {
Roman Elizarov32d95322017-02-09 15:57:31 +0300731 doSomethingUsefulTwo()
732}
733```
734
735Note, that these `asyncXXX` function are **not** _suspending_ functions. They can be used from anywhere.
736However, their use always implies asynchronous (here meaning _concurrent_) execution of their action
737with the invoking code.
738
739The following example shows their use outside of coroutine:
740
741```kotlin
742// note, that we don't have `runBlocking` to the right of `main` in this example
743fun main(args: Array<String>) {
744 val time = measureTimeMillis {
745 // we can initiate async actions outside of a coroutine
746 val one = asyncSomethingUsefulOne()
747 val two = asyncSomethingUsefulTwo()
748 // but waiting for a result must involve either suspending or blocking.
749 // here we use `runBlocking { ... }` to block the main thread while waiting for the result
750 runBlocking {
751 println("The answer is ${one.await() + two.await()}")
752 }
753 }
754 println("Completed in $time ms")
755}
756```
757
Roman Elizarove8d79342017-08-29 15:21:21 +0300758> You can get full code [here](core/kotlinx-coroutines-core/src/test/kotlin/guide/example-compose-04.kt)
Roman Elizarov1293ccd2017-02-01 18:49:54 +0300759
Roman Elizarov35d2c342017-07-20 14:54:39 +0300760<!--- TEST ARBITRARY_TIME
Roman Elizarov731f0ad2017-02-22 20:48:45 +0300761The answer is 42
762Completed in 1085 ms
763-->
764
Roman Elizarov2f6d7c92017-02-03 15:16:07 +0300765## Coroutine context and dispatchers
766
Roman Elizarov66f018c2017-09-29 21:39:03 +0300767Coroutines always execute in some context which is represented by the value of
768[CoroutineContext](https://kotlinlang.org/api/latest/jvm/stdlib/kotlin.coroutines.experimental/-coroutine-context/)
769type, defined in the Kotlin standard library.
770
771The coroutine context is a set of various elements. The main elements are the [Job] of the coroutine,
772which we've seen before, and its dispatcher, which is covered in this section.
Roman Elizarov2f6d7c92017-02-03 15:16:07 +0300773
774### Dispatchers and threads
775
Roman Elizarov66f018c2017-09-29 21:39:03 +0300776Coroutine context includes a _coroutine dispatcher_ (see [CoroutineDispatcher]) that determines what thread or threads
Roman Elizarov2f6d7c92017-02-03 15:16:07 +0300777the corresponding coroutine uses for its execution. Coroutine dispatcher can confine coroutine execution
Roman Elizarov66f018c2017-09-29 21:39:03 +0300778to a specific thread, dispatch it to a thread pool, or let it run unconfined.
779
780All coroutines builders like [launch] and [async] accept an optional
781[CoroutineContext](https://kotlinlang.org/api/latest/jvm/stdlib/kotlin.coroutines.experimental/-coroutine-context/)
782parameter that can be used to explicitly specify the dispatcher for new coroutine and other context elements.
783
784Try the following example:
Roman Elizarov2f6d7c92017-02-03 15:16:07 +0300785
786```kotlin
787fun main(args: Array<String>) = runBlocking<Unit> {
788 val jobs = arrayListOf<Job>()
789 jobs += launch(Unconfined) { // not confined -- will work with main thread
Roman Elizarov43e3af72017-07-21 16:01:31 +0300790 println(" 'Unconfined': I'm working in thread ${Thread.currentThread().name}")
Roman Elizarov2f6d7c92017-02-03 15:16:07 +0300791 }
Roman Elizarov43e3af72017-07-21 16:01:31 +0300792 jobs += launch(coroutineContext) { // context of the parent, runBlocking coroutine
793 println("'coroutineContext': I'm working in thread ${Thread.currentThread().name}")
Roman Elizarov2f6d7c92017-02-03 15:16:07 +0300794 }
795 jobs += launch(CommonPool) { // will get dispatched to ForkJoinPool.commonPool (or equivalent)
Roman Elizarov43e3af72017-07-21 16:01:31 +0300796 println(" 'CommonPool': I'm working in thread ${Thread.currentThread().name}")
Roman Elizarov2f6d7c92017-02-03 15:16:07 +0300797 }
798 jobs += launch(newSingleThreadContext("MyOwnThread")) { // will get its own new thread
Roman Elizarov43e3af72017-07-21 16:01:31 +0300799 println(" 'newSTC': I'm working in thread ${Thread.currentThread().name}")
Roman Elizarov2f6d7c92017-02-03 15:16:07 +0300800 }
801 jobs.forEach { it.join() }
802}
803```
804
Roman Elizarove8d79342017-08-29 15:21:21 +0300805> You can get full code [here](core/kotlinx-coroutines-core/src/test/kotlin/guide/example-context-01.kt)
Roman Elizarov2f6d7c92017-02-03 15:16:07 +0300806
807It produces the following output (maybe in different order):
808
Roman Elizarov731f0ad2017-02-22 20:48:45 +0300809```text
Roman Elizarov43e3af72017-07-21 16:01:31 +0300810 'Unconfined': I'm working in thread main
811 'CommonPool': I'm working in thread ForkJoinPool.commonPool-worker-1
812 'newSTC': I'm working in thread MyOwnThread
813'coroutineContext': I'm working in thread main
Roman Elizarov2f6d7c92017-02-03 15:16:07 +0300814```
815
Roman Elizarov731f0ad2017-02-22 20:48:45 +0300816<!--- TEST LINES_START_UNORDERED -->
817
Roman Elizarovd9ae2bc2017-10-20 17:36:56 +0800818The default dispatcher that we've used in previous sections is representend by [DefaultDispatcher], which
Roman Elizarov66f018c2017-09-29 21:39:03 +0300819is equal to [CommonPool] in the current implementation. So, `launch { ... }` is the same
820as `launch(DefaultDispather) { ... }`, which is the same as `launch(CommonPool) { ... }`.
821
Roman Elizarov43e3af72017-07-21 16:01:31 +0300822The difference between parent [coroutineContext][CoroutineScope.coroutineContext] and
823[Unconfined] context will be shown later.
Roman Elizarov2f6d7c92017-02-03 15:16:07 +0300824
Roman Elizarovd9ae2bc2017-10-20 17:36:56 +0800825Note, that [newSingleThreadContext] creates a new thread, which is a very expensive resource.
826In a real application it must be either released, when no longer needed, using [close][ThreadPoolDispatcher.close]
827function, or stored in a top-level variable and reused throughout the application.
828
Roman Elizarov2f6d7c92017-02-03 15:16:07 +0300829### Unconfined vs confined dispatcher
830
Roman Elizarov419a6c82017-02-09 18:36:22 +0300831The [Unconfined] coroutine dispatcher starts coroutine in the caller thread, but only until the
Roman Elizarov2f6d7c92017-02-03 15:16:07 +0300832first suspension point. After suspension it resumes in the thread that is fully determined by the
833suspending function that was invoked. Unconfined dispatcher is appropriate when coroutine does not
834consume CPU time nor updates any shared data (like UI) that is confined to a specific thread.
835
Roman Elizarov43e3af72017-07-21 16:01:31 +0300836On the other side, [coroutineContext][CoroutineScope.coroutineContext] property that is available inside the block of any coroutine
Roman Elizarov419a6c82017-02-09 18:36:22 +0300837via [CoroutineScope] interface, is a reference to a context of this particular coroutine.
Roman Elizarov66f018c2017-09-29 21:39:03 +0300838This way, a parent context can be inherited. The default dispatcher for [runBlocking] coroutine, in particular,
839is confined to the invoker thread, so inheriting it has the effect of confining execution to
Roman Elizarov2f6d7c92017-02-03 15:16:07 +0300840this thread with a predictable FIFO scheduling.
841
842```kotlin
843fun main(args: Array<String>) = runBlocking<Unit> {
844 val jobs = arrayListOf<Job>()
845 jobs += launch(Unconfined) { // not confined -- will work with main thread
Roman Elizarov43e3af72017-07-21 16:01:31 +0300846 println(" 'Unconfined': I'm working in thread ${Thread.currentThread().name}")
Roman Elizarovd0021622017-03-10 15:43:38 +0300847 delay(500)
Roman Elizarov43e3af72017-07-21 16:01:31 +0300848 println(" 'Unconfined': After delay in thread ${Thread.currentThread().name}")
Roman Elizarov2f6d7c92017-02-03 15:16:07 +0300849 }
Roman Elizarov43e3af72017-07-21 16:01:31 +0300850 jobs += launch(coroutineContext) { // context of the parent, runBlocking coroutine
851 println("'coroutineContext': I'm working in thread ${Thread.currentThread().name}")
Roman Elizarov2f6d7c92017-02-03 15:16:07 +0300852 delay(1000)
Roman Elizarov43e3af72017-07-21 16:01:31 +0300853 println("'coroutineContext': After delay in thread ${Thread.currentThread().name}")
Roman Elizarov2f6d7c92017-02-03 15:16:07 +0300854 }
855 jobs.forEach { it.join() }
856}
857```
858
Roman Elizarove8d79342017-08-29 15:21:21 +0300859> You can get full code [here](core/kotlinx-coroutines-core/src/test/kotlin/guide/example-context-02.kt)
Roman Elizarov2f6d7c92017-02-03 15:16:07 +0300860
861Produces the output:
862
Roman Elizarov731f0ad2017-02-22 20:48:45 +0300863```text
Roman Elizarov43e3af72017-07-21 16:01:31 +0300864 'Unconfined': I'm working in thread main
865'coroutineContext': I'm working in thread main
866 'Unconfined': After delay in thread kotlinx.coroutines.DefaultExecutor
867'coroutineContext': After delay in thread main
Roman Elizarov2f6d7c92017-02-03 15:16:07 +0300868```
Roman Elizarov731f0ad2017-02-22 20:48:45 +0300869
870<!--- TEST LINES_START -->
Roman Elizarov2f6d7c92017-02-03 15:16:07 +0300871
Roman Elizarov43e3af72017-07-21 16:01:31 +0300872So, the coroutine that had inherited `coroutineContext` of `runBlocking {...}` continues to execute
873in the `main` thread, while the unconfined one had resumed in the default executor thread that [delay]
874function is using.
Roman Elizarov2f6d7c92017-02-03 15:16:07 +0300875
876### Debugging coroutines and threads
877
Roman Elizarov419a6c82017-02-09 18:36:22 +0300878Coroutines can suspend on one thread and resume on another thread with [Unconfined] dispatcher or
Roman Elizarov66f018c2017-09-29 21:39:03 +0300879with a default multi-threaded dispatcher. Even with a single-threaded dispatcher it might be hard to
Roman Elizarov2f6d7c92017-02-03 15:16:07 +0300880figure out what coroutine was doing what, where, and when. The common approach to debugging applications with
881threads is to print the thread name in the log file on each log statement. This feature is universally supported
882by logging frameworks. When using coroutines, the thread name alone does not give much of a context, so
883`kotlinx.coroutines` includes debugging facilities to make it easier.
884
885Run the following code with `-Dkotlinx.coroutines.debug` JVM option:
886
887```kotlin
888fun log(msg: String) = println("[${Thread.currentThread().name}] $msg")
889
890fun main(args: Array<String>) = runBlocking<Unit> {
Roman Elizarov43e3af72017-07-21 16:01:31 +0300891 val a = async(coroutineContext) {
Roman Elizarov2f6d7c92017-02-03 15:16:07 +0300892 log("I'm computing a piece of the answer")
893 6
894 }
Roman Elizarov43e3af72017-07-21 16:01:31 +0300895 val b = async(coroutineContext) {
Roman Elizarov2f6d7c92017-02-03 15:16:07 +0300896 log("I'm computing another piece of the answer")
897 7
898 }
899 log("The answer is ${a.await() * b.await()}")
900}
901```
902
Roman Elizarove8d79342017-08-29 15:21:21 +0300903> You can get full code [here](core/kotlinx-coroutines-core/src/test/kotlin/guide/example-context-03.kt)
Roman Elizarov2f6d7c92017-02-03 15:16:07 +0300904
Roman Elizarovb7721cf2017-02-03 19:23:08 +0300905There are three coroutines. The main coroutine (#1) -- `runBlocking` one,
Roman Elizarov2f6d7c92017-02-03 15:16:07 +0300906and two coroutines computing deferred values `a` (#2) and `b` (#3).
907They are all executing in the context of `runBlocking` and are confined to the main thread.
908The output of this code is:
909
Roman Elizarov731f0ad2017-02-22 20:48:45 +0300910```text
Roman Elizarov2f6d7c92017-02-03 15:16:07 +0300911[main @coroutine#2] I'm computing a piece of the answer
912[main @coroutine#3] I'm computing another piece of the answer
913[main @coroutine#1] The answer is 42
914```
915
Kirill Timofeeva5186962017-10-25 14:25:47 +0300916<!--- TEST FLEXIBLE_THREAD -->
Roman Elizarov731f0ad2017-02-22 20:48:45 +0300917
Roman Elizarov2f6d7c92017-02-03 15:16:07 +0300918The `log` function prints the name of the thread in square brackets and you can see, that it is the `main`
919thread, but the identifier of the currently executing coroutine is appended to it. This identifier
920is consecutively assigned to all created coroutines when debugging mode is turned on.
921
Roman Elizarov419a6c82017-02-09 18:36:22 +0300922You can read more about debugging facilities in the documentation for [newCoroutineContext] function.
Roman Elizarov2f6d7c92017-02-03 15:16:07 +0300923
924### Jumping between threads
925
926Run the following code with `-Dkotlinx.coroutines.debug` JVM option:
927
928```kotlin
929fun log(msg: String) = println("[${Thread.currentThread().name}] $msg")
930
931fun main(args: Array<String>) {
Roman Elizarovd9ae2bc2017-10-20 17:36:56 +0800932 newSingleThreadContext("Ctx1").use { ctx1 ->
933 newSingleThreadContext("Ctx2").use { ctx2 ->
934 runBlocking(ctx1) {
935 log("Started in ctx1")
936 run(ctx2) {
937 log("Working in ctx2")
938 }
939 log("Back to ctx1")
940 }
Roman Elizarov2f6d7c92017-02-03 15:16:07 +0300941 }
Roman Elizarov2f6d7c92017-02-03 15:16:07 +0300942 }
943}
944```
945
Roman Elizarove8d79342017-08-29 15:21:21 +0300946> You can get full code [here](core/kotlinx-coroutines-core/src/test/kotlin/guide/example-context-04.kt)
Roman Elizarov2f6d7c92017-02-03 15:16:07 +0300947
Roman Elizarovd9ae2bc2017-10-20 17:36:56 +0800948It demonstrates several new techniques. One is using [runBlocking] with an explicitly specified context, and
949the other one is using [run] function to change a context of a coroutine while still staying in the
Roman Elizarov2f6d7c92017-02-03 15:16:07 +0300950same coroutine as you can see in the output below:
951
Roman Elizarov731f0ad2017-02-22 20:48:45 +0300952```text
Roman Elizarov2f6d7c92017-02-03 15:16:07 +0300953[Ctx1 @coroutine#1] Started in ctx1
954[Ctx2 @coroutine#1] Working in ctx2
955[Ctx1 @coroutine#1] Back to ctx1
956```
957
Roman Elizarov731f0ad2017-02-22 20:48:45 +0300958<!--- TEST -->
959
Roman Elizarovd9ae2bc2017-10-20 17:36:56 +0800960
961Note, that is example also uses `use` function from the Kotlin standard library to release threads that
962are created with [newSingleThreadContext] when they are no longer needed.
963
Roman Elizarov2f6d7c92017-02-03 15:16:07 +0300964### Job in the context
965
Roman Elizarov66f018c2017-09-29 21:39:03 +0300966The coroutine's [Job] is part of its context. The coroutine can retrieve it from its own context
Roman Elizarov43e3af72017-07-21 16:01:31 +0300967using `coroutineContext[Job]` expression:
Roman Elizarov2f6d7c92017-02-03 15:16:07 +0300968
969```kotlin
970fun main(args: Array<String>) = runBlocking<Unit> {
Roman Elizarov43e3af72017-07-21 16:01:31 +0300971 println("My job is ${coroutineContext[Job]}")
Roman Elizarov2f6d7c92017-02-03 15:16:07 +0300972}
973```
974
Roman Elizarove8d79342017-08-29 15:21:21 +0300975> You can get full code [here](core/kotlinx-coroutines-core/src/test/kotlin/guide/example-context-05.kt)
Roman Elizarov2f6d7c92017-02-03 15:16:07 +0300976
Roman Elizarov66f018c2017-09-29 21:39:03 +0300977It produces something like that when running in [debug mode](#debugging-coroutines-and-threads):
Roman Elizarov2f6d7c92017-02-03 15:16:07 +0300978
979```
Roman Elizarov8b38fa22017-09-27 17:44:31 +0300980My job is "coroutine#1":BlockingCoroutine{Active}@6d311334
Roman Elizarov2f6d7c92017-02-03 15:16:07 +0300981```
982
Roman Elizarov8b38fa22017-09-27 17:44:31 +0300983<!--- TEST lines.size == 1 && lines[0].startsWith("My job is \"coroutine#1\":BlockingCoroutine{Active}@") -->
Roman Elizarov731f0ad2017-02-22 20:48:45 +0300984
Roman Elizarov43e3af72017-07-21 16:01:31 +0300985So, [isActive][CoroutineScope.isActive] in [CoroutineScope] is just a convenient shortcut for
986`coroutineContext[Job]!!.isActive`.
Roman Elizarov2f6d7c92017-02-03 15:16:07 +0300987
988### Children of a coroutine
989
Roman Elizarov43e3af72017-07-21 16:01:31 +0300990When [coroutineContext][CoroutineScope.coroutineContext] of a coroutine is used to launch another coroutine,
Roman Elizarov419a6c82017-02-09 18:36:22 +0300991the [Job] of the new coroutine becomes
Roman Elizarov2f6d7c92017-02-03 15:16:07 +0300992a _child_ of the parent coroutine's job. When the parent coroutine is cancelled, all its children
993are recursively cancelled, too.
994
995```kotlin
996fun main(args: Array<String>) = runBlocking<Unit> {
Roman Elizarov66f018c2017-09-29 21:39:03 +0300997 // launch a coroutine to process some kind of incoming request
998 val request = launch {
Roman Elizarov2f6d7c92017-02-03 15:16:07 +0300999 // it spawns two other jobs, one with its separate context
Roman Elizarov66f018c2017-09-29 21:39:03 +03001000 val job1 = launch {
Roman Elizarov2f6d7c92017-02-03 15:16:07 +03001001 println("job1: I have my own context and execute independently!")
1002 delay(1000)
1003 println("job1: I am not affected by cancellation of the request")
1004 }
1005 // and the other inherits the parent context
Roman Elizarov43e3af72017-07-21 16:01:31 +03001006 val job2 = launch(coroutineContext) {
Roman Elizarov74619c12017-11-09 10:32:15 +03001007 delay(100)
Roman Elizarov2f6d7c92017-02-03 15:16:07 +03001008 println("job2: I am a child of the request coroutine")
1009 delay(1000)
1010 println("job2: I will not execute this line if my parent request is cancelled")
1011 }
1012 // request completes when both its sub-jobs complete:
1013 job1.join()
1014 job2.join()
1015 }
1016 delay(500)
1017 request.cancel() // cancel processing of the request
1018 delay(1000) // delay a second to see what happens
1019 println("main: Who has survived request cancellation?")
1020}
1021```
1022
Roman Elizarove8d79342017-08-29 15:21:21 +03001023> You can get full code [here](core/kotlinx-coroutines-core/src/test/kotlin/guide/example-context-06.kt)
Roman Elizarov2f6d7c92017-02-03 15:16:07 +03001024
1025The output of this code is:
1026
Roman Elizarov731f0ad2017-02-22 20:48:45 +03001027```text
Roman Elizarov2f6d7c92017-02-03 15:16:07 +03001028job1: I have my own context and execute independently!
1029job2: I am a child of the request coroutine
1030job1: I am not affected by cancellation of the request
1031main: Who has survived request cancellation?
1032```
1033
Roman Elizarov731f0ad2017-02-22 20:48:45 +03001034<!--- TEST -->
1035
Roman Elizarov2f6d7c92017-02-03 15:16:07 +03001036### Combining contexts
1037
Roman Elizarov66f018c2017-09-29 21:39:03 +03001038Coroutine contexts can be combined using `+` operator. The context on the right-hand side replaces relevant entries
Roman Elizarov419a6c82017-02-09 18:36:22 +03001039of 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 +03001040its dispatcher replaced:
1041
1042```kotlin
1043fun main(args: Array<String>) = runBlocking<Unit> {
1044 // start a coroutine to process some kind of incoming request
Roman Elizarov43e3af72017-07-21 16:01:31 +03001045 val request = launch(coroutineContext) { // use the context of `runBlocking`
Roman Elizarov2f6d7c92017-02-03 15:16:07 +03001046 // spawns CPU-intensive child job in CommonPool !!!
Roman Elizarov43e3af72017-07-21 16:01:31 +03001047 val job = launch(coroutineContext + CommonPool) {
Roman Elizarov2f6d7c92017-02-03 15:16:07 +03001048 println("job: I am a child of the request coroutine, but with a different dispatcher")
1049 delay(1000)
1050 println("job: I will not execute this line if my parent request is cancelled")
1051 }
1052 job.join() // request completes when its sub-job completes
1053 }
1054 delay(500)
1055 request.cancel() // cancel processing of the request
1056 delay(1000) // delay a second to see what happens
1057 println("main: Who has survived request cancellation?")
1058}
1059```
1060
Roman Elizarove8d79342017-08-29 15:21:21 +03001061> You can get full code [here](core/kotlinx-coroutines-core/src/test/kotlin/guide/example-context-07.kt)
Roman Elizarov2f6d7c92017-02-03 15:16:07 +03001062
1063The expected outcome of this code is:
1064
Roman Elizarov731f0ad2017-02-22 20:48:45 +03001065```text
Roman Elizarov2f6d7c92017-02-03 15:16:07 +03001066job: I am a child of the request coroutine, but with a different dispatcher
1067main: Who has survived request cancellation?
1068```
1069
Roman Elizarov731f0ad2017-02-22 20:48:45 +03001070<!--- TEST -->
1071
Roman Elizarov8b38fa22017-09-27 17:44:31 +03001072### Parental responsibilities
1073
1074A parent coroutine always waits for completion of all its children. Parent does not have to explicitly track
Roman Elizarov88396732017-09-27 21:30:47 +03001075all 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 +03001076
1077```kotlin
1078fun main(args: Array<String>) = runBlocking<Unit> {
Roman Elizarov66f018c2017-09-29 21:39:03 +03001079 // launch a coroutine to process some kind of incoming request
1080 val request = launch {
Roman Elizarov8b38fa22017-09-27 17:44:31 +03001081 repeat(3) { i -> // launch a few children jobs
1082 launch(coroutineContext) {
1083 delay((i + 1) * 200L) // variable delay 200ms, 400ms, 600ms
1084 println("Coroutine $i is done")
1085 }
1086 }
1087 println("request: I'm done and I don't explicitly join my children that are still active")
1088 }
1089 request.join() // wait for completion of the request, including all its children
1090 println("Now processing of the request is complete")
1091}
1092```
1093
1094> You can get full code [here](core/kotlinx-coroutines-core/src/test/kotlin/guide/example-context-08.kt)
1095
1096The result is going to be:
1097
1098```text
1099request: I'm done and I don't explicitly join my children that are still active
1100Coroutine 0 is done
1101Coroutine 1 is done
1102Coroutine 2 is done
1103Now processing of the request is complete
1104```
1105
1106<!--- TEST -->
1107
Roman Elizarov2f6d7c92017-02-03 15:16:07 +03001108### Naming coroutines for debugging
1109
Roman Elizarovb7721cf2017-02-03 19:23:08 +03001110Automatically assigned ids are good when coroutines log often and you just need to correlate log records
Roman Elizarov2f6d7c92017-02-03 15:16:07 +03001111coming from the same coroutine. However, when coroutine is tied to the processing of a specific request
1112or doing some specific background task, it is better to name it explicitly for debugging purposes.
Roman Elizarov66f018c2017-09-29 21:39:03 +03001113[CoroutineName] context element serves the same function as a thread name. It'll get displayed in the thread name that
1114is executing this coroutine when [debugging mode](#debugging-coroutines-and-threads) is turned on.
Roman Elizarov2f6d7c92017-02-03 15:16:07 +03001115
1116The following example demonstrates this concept:
1117
1118```kotlin
1119fun log(msg: String) = println("[${Thread.currentThread().name}] $msg")
1120
1121fun main(args: Array<String>) = runBlocking(CoroutineName("main")) {
1122 log("Started main coroutine")
1123 // run two background value computations
Roman Elizarov66f018c2017-09-29 21:39:03 +03001124 val v1 = async(CoroutineName("v1coroutine")) {
Roman Elizarov2f6d7c92017-02-03 15:16:07 +03001125 delay(500)
Roman Elizarov674efea2017-10-21 17:16:30 +03001126 log("Computing v1")
Roman Elizarov2f6d7c92017-02-03 15:16:07 +03001127 252
1128 }
Roman Elizarov66f018c2017-09-29 21:39:03 +03001129 val v2 = async(CoroutineName("v2coroutine")) {
Roman Elizarov2f6d7c92017-02-03 15:16:07 +03001130 delay(1000)
Roman Elizarov674efea2017-10-21 17:16:30 +03001131 log("Computing v2")
Roman Elizarov2f6d7c92017-02-03 15:16:07 +03001132 6
1133 }
1134 log("The answer for v1 / v2 = ${v1.await() / v2.await()}")
1135}
1136```
1137
Roman Elizarov8b38fa22017-09-27 17:44:31 +03001138> You can get full code [here](core/kotlinx-coroutines-core/src/test/kotlin/guide/example-context-09.kt)
Roman Elizarov2f6d7c92017-02-03 15:16:07 +03001139
1140The output it produces with `-Dkotlinx.coroutines.debug` JVM option is similar to:
1141
Roman Elizarov731f0ad2017-02-22 20:48:45 +03001142```text
Roman Elizarov2f6d7c92017-02-03 15:16:07 +03001143[main @main#1] Started main coroutine
1144[ForkJoinPool.commonPool-worker-1 @v1coroutine#2] Computing v1
1145[ForkJoinPool.commonPool-worker-2 @v2coroutine#3] Computing v2
1146[main @main#1] The answer for v1 / v2 = 42
1147```
Roman Elizarov1293ccd2017-02-01 18:49:54 +03001148
Roman Elizarov731f0ad2017-02-22 20:48:45 +03001149<!--- TEST FLEXIBLE_THREAD -->
1150
Roman Elizarov2fd7cb32017-02-11 23:18:59 +03001151### Cancellation via explicit job
1152
1153Let us put our knowledge about contexts, children and jobs together. Assume that our application has
1154an object with a lifecycle, but that object is not a coroutine. For example, we are writing an Android application
1155and launch various coroutines in the context of an Android activity to perform asynchronous operations to fetch
1156and update data, do animations, etc. All of these coroutines must be cancelled when activity is destroyed
1157to avoid memory leaks.
1158
1159We can manage a lifecycle of our coroutines by creating an instance of [Job] that is tied to
Roman Elizarov88396732017-09-27 21:30:47 +03001160the lifecycle of our activity. A job instance is created using [Job()] factory function
Roman Elizarov2fd7cb32017-02-11 23:18:59 +03001161as the following example shows. We need to make sure that all the coroutines are started
1162with this job in their context and then a single invocation of [Job.cancel] terminates them all.
Roman Elizarov8b38fa22017-09-27 17:44:31 +03001163Moreover, [Job.join] waits for all of them to complete, so we can also use [cancelAndJoin] here in
1164this example:
Roman Elizarov2fd7cb32017-02-11 23:18:59 +03001165
1166```kotlin
1167fun main(args: Array<String>) = runBlocking<Unit> {
1168 val job = Job() // create a job object to manage our lifecycle
1169 // now launch ten coroutines for a demo, each working for a different time
1170 val coroutines = List(10) { i ->
1171 // they are all children of our job object
Roman Elizarov43e3af72017-07-21 16:01:31 +03001172 launch(coroutineContext + job) { // we use the context of main runBlocking thread, but with our own job object
Roman Elizarov8b38fa22017-09-27 17:44:31 +03001173 delay((i + 1) * 200L) // variable delay 200ms, 400ms, ... etc
Roman Elizarov2fd7cb32017-02-11 23:18:59 +03001174 println("Coroutine $i is done")
1175 }
1176 }
1177 println("Launched ${coroutines.size} coroutines")
1178 delay(500L) // delay for half a second
Roman Elizarov8b38fa22017-09-27 17:44:31 +03001179 println("Cancelling the job!")
1180 job.cancelAndJoin() // cancel all our coroutines and wait for all of them to complete
Roman Elizarov2fd7cb32017-02-11 23:18:59 +03001181}
1182```
1183
Roman Elizarov8b38fa22017-09-27 17:44:31 +03001184> You can get full code [here](core/kotlinx-coroutines-core/src/test/kotlin/guide/example-context-10.kt)
Roman Elizarov2fd7cb32017-02-11 23:18:59 +03001185
1186The output of this example is:
1187
Roman Elizarov731f0ad2017-02-22 20:48:45 +03001188```text
Roman Elizarov2fd7cb32017-02-11 23:18:59 +03001189Launched 10 coroutines
1190Coroutine 0 is done
1191Coroutine 1 is done
Roman Elizarov8b38fa22017-09-27 17:44:31 +03001192Cancelling the job!
Roman Elizarov2fd7cb32017-02-11 23:18:59 +03001193```
1194
Roman Elizarov731f0ad2017-02-22 20:48:45 +03001195<!--- TEST -->
1196
Roman Elizarov2fd7cb32017-02-11 23:18:59 +03001197As you can see, only the first three coroutines had printed a message and the others were cancelled
Roman Elizarov8b38fa22017-09-27 17:44:31 +03001198by a single invocation of `job.cancelAndJoin()`. So all we need to do in our hypothetical Android
Roman Elizarov2fd7cb32017-02-11 23:18:59 +03001199application is to create a parent job object when activity is created, use it for child coroutines,
Roman Elizarov8b38fa22017-09-27 17:44:31 +03001200and cancel it when activity is destroyed. We cannot `join` them in the case of Android lifecycle,
1201since it is synchronous, but this joining ability is useful when building backend services to ensure bounded
1202resource usage.
Roman Elizarov2fd7cb32017-02-11 23:18:59 +03001203
Roman Elizarovb7721cf2017-02-03 19:23:08 +03001204## Channels
Roman Elizarov7deefb82017-01-31 10:33:17 +03001205
Roman Elizarovb7721cf2017-02-03 19:23:08 +03001206Deferred values provide a convenient way to transfer a single value between coroutines.
1207Channels provide a way to transfer a stream of values.
1208
1209<!--- INCLUDE .*/example-channel-([0-9]+).kt
1210import kotlinx.coroutines.experimental.channels.*
1211-->
1212
1213### Channel basics
1214
Roman Elizarov419a6c82017-02-09 18:36:22 +03001215A [Channel] is conceptually very similar to `BlockingQueue`. One key difference is that
1216instead of a blocking `put` operation it has a suspending [send][SendChannel.send], and instead of
1217a blocking `take` operation it has a suspending [receive][ReceiveChannel.receive].
Roman Elizarovb7721cf2017-02-03 19:23:08 +03001218
1219```kotlin
1220fun main(args: Array<String>) = runBlocking<Unit> {
1221 val channel = Channel<Int>()
Roman Elizarov66f018c2017-09-29 21:39:03 +03001222 launch {
Roman Elizarovb7721cf2017-02-03 19:23:08 +03001223 // this might be heavy CPU-consuming computation or async logic, we'll just send five squares
1224 for (x in 1..5) channel.send(x * x)
1225 }
1226 // here we print five received integers:
1227 repeat(5) { println(channel.receive()) }
1228 println("Done!")
1229}
1230```
1231
Roman Elizarove8d79342017-08-29 15:21:21 +03001232> You can get full code [here](core/kotlinx-coroutines-core/src/test/kotlin/guide/example-channel-01.kt)
Roman Elizarovb7721cf2017-02-03 19:23:08 +03001233
Roman Elizarov731f0ad2017-02-22 20:48:45 +03001234The output of this code is:
1235
1236```text
12371
12384
12399
124016
124125
1242Done!
1243```
1244
1245<!--- TEST -->
1246
Roman Elizarovb7721cf2017-02-03 19:23:08 +03001247### Closing and iteration over channels
1248
1249Unlike a queue, a channel can be closed to indicate that no more elements are coming.
1250On the receiver side it is convenient to use a regular `for` loop to receive elements
1251from the channel.
1252
Roman Elizarov419a6c82017-02-09 18:36:22 +03001253Conceptually, a [close][SendChannel.close] is like sending a special close token to the channel.
Roman Elizarovb7721cf2017-02-03 19:23:08 +03001254The iteration stops as soon as this close token is received, so there is a guarantee
1255that all previously sent elements before the close are received:
1256
1257```kotlin
1258fun main(args: Array<String>) = runBlocking<Unit> {
1259 val channel = Channel<Int>()
Roman Elizarov66f018c2017-09-29 21:39:03 +03001260 launch {
Roman Elizarovb7721cf2017-02-03 19:23:08 +03001261 for (x in 1..5) channel.send(x * x)
1262 channel.close() // we're done sending
1263 }
1264 // here we print received values using `for` loop (until the channel is closed)
1265 for (y in channel) println(y)
1266 println("Done!")
1267}
1268```
1269
Roman Elizarove8d79342017-08-29 15:21:21 +03001270> You can get full code [here](core/kotlinx-coroutines-core/src/test/kotlin/guide/example-channel-02.kt)
Roman Elizarovb7721cf2017-02-03 19:23:08 +03001271
Roman Elizarov731f0ad2017-02-22 20:48:45 +03001272<!--- TEST
12731
12744
12759
127616
127725
1278Done!
1279-->
1280
Roman Elizarovb7721cf2017-02-03 19:23:08 +03001281### Building channel producers
1282
Roman Elizarova5e653f2017-02-13 13:49:55 +03001283The pattern where a coroutine is producing a sequence of elements is quite common.
1284This is a part of _producer-consumer_ pattern that is often found in concurrent code.
Roman Elizarovb7721cf2017-02-03 19:23:08 +03001285You 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 +03001286to common sense that results must be returned from functions.
1287
Roman Elizarov86349be2017-03-17 16:47:37 +03001288There 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 +03001289and an extension function [consumeEach], that replaces a `for` loop on the consumer side:
Roman Elizarovb7721cf2017-02-03 19:23:08 +03001290
1291```kotlin
Roman Elizarov66f018c2017-09-29 21:39:03 +03001292fun produceSquares() = produce<Int> {
Roman Elizarovb7721cf2017-02-03 19:23:08 +03001293 for (x in 1..5) send(x * x)
1294}
1295
1296fun main(args: Array<String>) = runBlocking<Unit> {
1297 val squares = produceSquares()
Roman Elizarov86349be2017-03-17 16:47:37 +03001298 squares.consumeEach { println(it) }
Roman Elizarovb7721cf2017-02-03 19:23:08 +03001299 println("Done!")
1300}
1301```
1302
Roman Elizarove8d79342017-08-29 15:21:21 +03001303> You can get full code [here](core/kotlinx-coroutines-core/src/test/kotlin/guide/example-channel-03.kt)
Roman Elizarovb7721cf2017-02-03 19:23:08 +03001304
Roman Elizarov731f0ad2017-02-22 20:48:45 +03001305<!--- TEST
13061
13074
13089
130916
131025
1311Done!
1312-->
1313
Roman Elizarovb7721cf2017-02-03 19:23:08 +03001314### Pipelines
1315
Roman Elizarov66f018c2017-09-29 21:39:03 +03001316A pipeline is a pattern where one coroutine is producing, possibly infinite, stream of values:
Roman Elizarovb7721cf2017-02-03 19:23:08 +03001317
1318```kotlin
Roman Elizarov66f018c2017-09-29 21:39:03 +03001319fun produceNumbers() = produce<Int> {
Roman Elizarovb7721cf2017-02-03 19:23:08 +03001320 var x = 1
1321 while (true) send(x++) // infinite stream of integers starting from 1
1322}
1323```
1324
Roman Elizarova5e653f2017-02-13 13:49:55 +03001325And another coroutine or coroutines are consuming that stream, doing some processing, and producing some other results.
Roman Elizarovb7721cf2017-02-03 19:23:08 +03001326In the below example the numbers are just squared:
1327
1328```kotlin
Roman Elizarov66f018c2017-09-29 21:39:03 +03001329fun square(numbers: ReceiveChannel<Int>) = produce<Int> {
Roman Elizarovb7721cf2017-02-03 19:23:08 +03001330 for (x in numbers) send(x * x)
1331}
1332```
1333
Roman Elizarova5e653f2017-02-13 13:49:55 +03001334The main code starts and connects the whole pipeline:
Roman Elizarovb7721cf2017-02-03 19:23:08 +03001335
1336```kotlin
1337fun main(args: Array<String>) = runBlocking<Unit> {
1338 val numbers = produceNumbers() // produces integers from 1 and on
1339 val squares = square(numbers) // squares integers
1340 for (i in 1..5) println(squares.receive()) // print first five
1341 println("Done!") // we are done
1342 squares.cancel() // need to cancel these coroutines in a larger app
1343 numbers.cancel()
1344}
1345```
1346
Roman Elizarove8d79342017-08-29 15:21:21 +03001347> You can get full code [here](core/kotlinx-coroutines-core/src/test/kotlin/guide/example-channel-04.kt)
Roman Elizarovb7721cf2017-02-03 19:23:08 +03001348
Roman Elizarov731f0ad2017-02-22 20:48:45 +03001349<!--- TEST
13501
13514
13529
135316
135425
1355Done!
1356-->
1357
Roman Elizarovb7721cf2017-02-03 19:23:08 +03001358We don't have to cancel these coroutines in this example app, because
1359[coroutines are like daemon threads](#coroutines-are-like-daemon-threads),
1360but in a larger app we'll need to stop our pipeline if we don't need it anymore.
1361Alternatively, we could have run pipeline coroutines as
Roman Elizarov66f018c2017-09-29 21:39:03 +03001362[children of a main coroutine](#children-of-a-coroutine) as is demonstrated in the following example.
Roman Elizarovb7721cf2017-02-03 19:23:08 +03001363
1364### Prime numbers with pipeline
1365
Cedric Beustfa0b28f2017-02-07 07:07:25 -08001366Let's take pipelines to the extreme with an example that generates prime numbers using a pipeline
Roman Elizarovb7721cf2017-02-03 19:23:08 +03001367of coroutines. We start with an infinite sequence of numbers. This time we introduce an
Roman Elizarov66f018c2017-09-29 21:39:03 +03001368explicit `context` parameter and pass it to [produce] builder,
1369so that caller can control where our coroutines run:
Roman Elizarovb7721cf2017-02-03 19:23:08 +03001370
Roman Elizarove8d79342017-08-29 15:21:21 +03001371<!--- INCLUDE core/kotlinx-coroutines-core/src/test/kotlin/guide/example-channel-05.kt
Roman Elizarovb7721cf2017-02-03 19:23:08 +03001372import kotlin.coroutines.experimental.CoroutineContext
1373-->
1374
1375```kotlin
Roman Elizarova5e653f2017-02-13 13:49:55 +03001376fun numbersFrom(context: CoroutineContext, start: Int) = produce<Int>(context) {
Roman Elizarovb7721cf2017-02-03 19:23:08 +03001377 var x = start
1378 while (true) send(x++) // infinite stream of integers from start
1379}
1380```
1381
1382The following pipeline stage filters an incoming stream of numbers, removing all the numbers
1383that are divisible by the given prime number:
1384
1385```kotlin
Roman Elizarova5e653f2017-02-13 13:49:55 +03001386fun filter(context: CoroutineContext, numbers: ReceiveChannel<Int>, prime: Int) = produce<Int>(context) {
Roman Elizarovb7721cf2017-02-03 19:23:08 +03001387 for (x in numbers) if (x % prime != 0) send(x)
1388}
1389```
1390
1391Now 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 +03001392and launching new pipeline stage for each prime number found:
1393
1394```
Roman Elizarova5e653f2017-02-13 13:49:55 +03001395numbersFrom(2) -> filter(2) -> filter(3) -> filter(5) -> filter(7) ...
Roman Elizarov62500ba2017-02-09 18:55:40 +03001396```
1397
1398The following example prints the first ten prime numbers,
Roman Elizarov8b38fa22017-09-27 17:44:31 +03001399running the whole pipeline in the context of the main thread. Since all the coroutines are launched as
1400children of the main [runBlocking] coroutine in its [coroutineContext][CoroutineScope.coroutineContext],
Roman Elizarov66f018c2017-09-29 21:39:03 +03001401we don't have to keep an explicit list of all the coroutine we have started.
Roman Elizarov88396732017-09-27 21:30:47 +03001402We use [cancelChildren] extension function to cancel all the children coroutines.
Roman Elizarovb7721cf2017-02-03 19:23:08 +03001403
1404```kotlin
1405fun main(args: Array<String>) = runBlocking<Unit> {
Roman Elizarov43e3af72017-07-21 16:01:31 +03001406 var cur = numbersFrom(coroutineContext, 2)
Roman Elizarovb7721cf2017-02-03 19:23:08 +03001407 for (i in 1..10) {
1408 val prime = cur.receive()
1409 println(prime)
Roman Elizarov43e3af72017-07-21 16:01:31 +03001410 cur = filter(coroutineContext, cur, prime)
Roman Elizarovb7721cf2017-02-03 19:23:08 +03001411 }
Roman Elizarov8b38fa22017-09-27 17:44:31 +03001412 coroutineContext.cancelChildren() // cancel all children to let main finish
Roman Elizarovb7721cf2017-02-03 19:23:08 +03001413}
1414```
1415
Roman Elizarove8d79342017-08-29 15:21:21 +03001416> You can get full code [here](core/kotlinx-coroutines-core/src/test/kotlin/guide/example-channel-05.kt)
Roman Elizarovb7721cf2017-02-03 19:23:08 +03001417
1418The output of this code is:
1419
Roman Elizarov731f0ad2017-02-22 20:48:45 +03001420```text
Roman Elizarovb7721cf2017-02-03 19:23:08 +030014212
14223
14235
14247
142511
142613
142717
142819
142923
143029
1431```
1432
Roman Elizarov731f0ad2017-02-22 20:48:45 +03001433<!--- TEST -->
1434
Roman Elizarov66f018c2017-09-29 21:39:03 +03001435Note, that you can build the same pipeline using
1436[`buildIterator`](https://kotlinlang.org/api/latest/jvm/stdlib/kotlin.coroutines.experimental/build-iterator.html)
1437coroutine builder from the standard library.
Roman Elizarova5e653f2017-02-13 13:49:55 +03001438Replace `produce` with `buildIterator`, `send` with `yield`, `receive` with `next`,
Roman Elizarov62500ba2017-02-09 18:55:40 +03001439`ReceiveChannel` with `Iterator`, and get rid of the context. You will not need `runBlocking` either.
1440However, the benefit of a pipeline that uses channels as shown above is that it can actually use
1441multiple CPU cores if you run it in [CommonPool] context.
1442
Roman Elizarova5e653f2017-02-13 13:49:55 +03001443Anyway, this is an extremely impractical way to find prime numbers. In practice, pipelines do involve some
Roman Elizarov62500ba2017-02-09 18:55:40 +03001444other suspending invocations (like asynchronous calls to remote services) and these pipelines cannot be
1445built using `buildSeqeunce`/`buildIterator`, because they do not allow arbitrary suspension, unlike
Roman Elizarov66f018c2017-09-29 21:39:03 +03001446`produce`, which is fully asynchronous.
Roman Elizarov62500ba2017-02-09 18:55:40 +03001447
Roman Elizarovb7721cf2017-02-03 19:23:08 +03001448### Fan-out
1449
1450Multiple coroutines may receive from the same channel, distributing work between themselves.
1451Let us start with a producer coroutine that is periodically producing integers
1452(ten numbers per second):
1453
1454```kotlin
Roman Elizarov66f018c2017-09-29 21:39:03 +03001455fun produceNumbers() = produce<Int> {
Roman Elizarovb7721cf2017-02-03 19:23:08 +03001456 var x = 1 // start from 1
1457 while (true) {
1458 send(x++) // produce next
1459 delay(100) // wait 0.1s
1460 }
1461}
1462```
1463
1464Then we can have several processor coroutines. In this example, they just print their id and
1465received number:
1466
1467```kotlin
Roman Elizarov66f018c2017-09-29 21:39:03 +03001468fun launchProcessor(id: Int, channel: ReceiveChannel<Int>) = launch {
Roman Elizarov86349be2017-03-17 16:47:37 +03001469 channel.consumeEach {
1470 println("Processor #$id received $it")
Roman Elizarovec9384c2017-03-02 22:09:08 +03001471 }
Roman Elizarovb7721cf2017-02-03 19:23:08 +03001472}
1473```
1474
Roman Elizarov35d2c342017-07-20 14:54:39 +03001475Now let us launch five processors and let them work for almost a second. See what happens:
Roman Elizarovb7721cf2017-02-03 19:23:08 +03001476
1477```kotlin
1478fun main(args: Array<String>) = runBlocking<Unit> {
1479 val producer = produceNumbers()
1480 repeat(5) { launchProcessor(it, producer) }
Roman Elizarov35d2c342017-07-20 14:54:39 +03001481 delay(950)
Roman Elizarovb7721cf2017-02-03 19:23:08 +03001482 producer.cancel() // cancel producer coroutine and thus kill them all
1483}
1484```
1485
Roman Elizarove8d79342017-08-29 15:21:21 +03001486> You can get full code [here](core/kotlinx-coroutines-core/src/test/kotlin/guide/example-channel-06.kt)
Roman Elizarovb7721cf2017-02-03 19:23:08 +03001487
1488The output will be similar to the the following one, albeit the processor ids that receive
1489each specific integer may be different:
1490
1491```
1492Processor #2 received 1
1493Processor #4 received 2
1494Processor #0 received 3
1495Processor #1 received 4
1496Processor #3 received 5
1497Processor #2 received 6
1498Processor #4 received 7
1499Processor #0 received 8
1500Processor #1 received 9
1501Processor #3 received 10
1502```
1503
Roman Elizarov731f0ad2017-02-22 20:48:45 +03001504<!--- TEST lines.size == 10 && lines.withIndex().all { (i, line) -> line.startsWith("Processor #") && line.endsWith(" received ${i + 1}") } -->
1505
Roman Elizarovb7721cf2017-02-03 19:23:08 +03001506Note, that cancelling a producer coroutine closes its channel, thus eventually terminating iteration
1507over the channel that processor coroutines are doing.
1508
1509### Fan-in
1510
1511Multiple coroutines may send to the same channel.
1512For example, let us have a channel of strings, and a suspending function that
1513repeatedly sends a specified string to this channel with a specified delay:
1514
1515```kotlin
1516suspend fun sendString(channel: SendChannel<String>, s: String, time: Long) {
1517 while (true) {
1518 delay(time)
1519 channel.send(s)
1520 }
1521}
1522```
1523
Cedric Beustfa0b28f2017-02-07 07:07:25 -08001524Now, let us see what happens if we launch a couple of coroutines sending strings
Roman Elizarov8b38fa22017-09-27 17:44:31 +03001525(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 +03001526
1527```kotlin
1528fun main(args: Array<String>) = runBlocking<Unit> {
1529 val channel = Channel<String>()
Roman Elizarov43e3af72017-07-21 16:01:31 +03001530 launch(coroutineContext) { sendString(channel, "foo", 200L) }
1531 launch(coroutineContext) { sendString(channel, "BAR!", 500L) }
Roman Elizarovb7721cf2017-02-03 19:23:08 +03001532 repeat(6) { // receive first six
1533 println(channel.receive())
1534 }
Roman Elizarov8b38fa22017-09-27 17:44:31 +03001535 coroutineContext.cancelChildren() // cancel all children to let main finish
Roman Elizarovb7721cf2017-02-03 19:23:08 +03001536}
1537```
1538
Roman Elizarove8d79342017-08-29 15:21:21 +03001539> You can get full code [here](core/kotlinx-coroutines-core/src/test/kotlin/guide/example-channel-07.kt)
Roman Elizarovb7721cf2017-02-03 19:23:08 +03001540
1541The output is:
1542
Roman Elizarov731f0ad2017-02-22 20:48:45 +03001543```text
Roman Elizarovb7721cf2017-02-03 19:23:08 +03001544foo
1545foo
1546BAR!
1547foo
1548foo
1549BAR!
1550```
1551
Roman Elizarov731f0ad2017-02-22 20:48:45 +03001552<!--- TEST -->
1553
Roman Elizarovb7721cf2017-02-03 19:23:08 +03001554### Buffered channels
1555
1556The channels shown so far had no buffer. Unbuffered channels transfer elements when sender and receiver
1557meet each other (aka rendezvous). If send is invoked first, then it is suspended until receive is invoked,
1558if receive is invoked first, it is suspended until send is invoked.
Roman Elizarov419a6c82017-02-09 18:36:22 +03001559
Roman Elizarov88396732017-09-27 21:30:47 +03001560Both [Channel()] factory function and [produce] builder take an optional `capacity` parameter to
Roman Elizarovb7721cf2017-02-03 19:23:08 +03001561specify _buffer size_. Buffer allows senders to send multiple elements before suspending,
1562similar to the `BlockingQueue` with a specified capacity, which blocks when buffer is full.
1563
1564Take a look at the behavior of the following code:
1565
1566```kotlin
1567fun main(args: Array<String>) = runBlocking<Unit> {
1568 val channel = Channel<Int>(4) // create buffered channel
Roman Elizarov8b38fa22017-09-27 17:44:31 +03001569 val sender = launch(coroutineContext) { // launch sender coroutine
Roman Elizarovb7721cf2017-02-03 19:23:08 +03001570 repeat(10) {
1571 println("Sending $it") // print before sending each element
1572 channel.send(it) // will suspend when buffer is full
1573 }
1574 }
1575 // don't receive anything... just wait....
1576 delay(1000)
Roman Elizarov8b38fa22017-09-27 17:44:31 +03001577 sender.cancel() // cancel sender coroutine
Roman Elizarovb7721cf2017-02-03 19:23:08 +03001578}
1579```
1580
Roman Elizarove8d79342017-08-29 15:21:21 +03001581> You can get full code [here](core/kotlinx-coroutines-core/src/test/kotlin/guide/example-channel-08.kt)
Roman Elizarovb7721cf2017-02-03 19:23:08 +03001582
1583It prints "sending" _five_ times using a buffered channel with capacity of _four_:
1584
Roman Elizarov731f0ad2017-02-22 20:48:45 +03001585```text
Roman Elizarovb7721cf2017-02-03 19:23:08 +03001586Sending 0
1587Sending 1
1588Sending 2
1589Sending 3
1590Sending 4
1591```
1592
Roman Elizarov731f0ad2017-02-22 20:48:45 +03001593<!--- TEST -->
1594
Roman Elizarovb7721cf2017-02-03 19:23:08 +03001595The 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 +03001596
Roman Elizarovb0517ba2017-02-27 14:03:14 +03001597### Channels are fair
1598
1599Send and receive operations to channels are _fair_ with respect to the order of their invocation from
1600multiple coroutines. They are served in first-in first-out order, e.g. the first coroutine to invoke `receive`
1601gets the element. In the following example two coroutines "ping" and "pong" are
1602receiving the "ball" object from the shared "table" channel.
1603
1604```kotlin
1605data class Ball(var hits: Int)
1606
1607fun main(args: Array<String>) = runBlocking<Unit> {
1608 val table = Channel<Ball>() // a shared table
Roman Elizarov43e3af72017-07-21 16:01:31 +03001609 launch(coroutineContext) { player("ping", table) }
1610 launch(coroutineContext) { player("pong", table) }
Roman Elizarovb0517ba2017-02-27 14:03:14 +03001611 table.send(Ball(0)) // serve the ball
1612 delay(1000) // delay 1 second
Roman Elizarov8b38fa22017-09-27 17:44:31 +03001613 coroutineContext.cancelChildren() // game over, cancel them
Roman Elizarovb0517ba2017-02-27 14:03:14 +03001614}
1615
1616suspend fun player(name: String, table: Channel<Ball>) {
1617 for (ball in table) { // receive the ball in a loop
1618 ball.hits++
1619 println("$name $ball")
Roman Elizarovf526b132017-03-10 16:07:14 +03001620 delay(300) // wait a bit
Roman Elizarovb0517ba2017-02-27 14:03:14 +03001621 table.send(ball) // send the ball back
1622 }
1623}
1624```
1625
Roman Elizarove8d79342017-08-29 15:21:21 +03001626> You can get full code [here](core/kotlinx-coroutines-core/src/test/kotlin/guide/example-channel-09.kt)
Roman Elizarovb0517ba2017-02-27 14:03:14 +03001627
1628The "ping" coroutine is started first, so it is the first one to receive the ball. Even though "ping"
1629coroutine immediately starts receiving the ball again after sending it back to the table, the ball gets
1630received by the "pong" coroutine, because it was already waiting for it:
1631
1632```text
1633ping Ball(hits=1)
1634pong Ball(hits=2)
1635ping Ball(hits=3)
1636pong Ball(hits=4)
Roman Elizarovb0517ba2017-02-27 14:03:14 +03001637```
1638
1639<!--- TEST -->
1640
Roman Elizarov8b38fa22017-09-27 17:44:31 +03001641Note, that sometimes channels may produce executions that look unfair due to the nature of the executor
1642that is being used. See [this issue](https://github.com/Kotlin/kotlinx.coroutines/issues/111) for details.
1643
Roman Elizarovf5bc0472017-02-22 11:38:13 +03001644## Shared mutable state and concurrency
1645
Roman Elizarov66f018c2017-09-29 21:39:03 +03001646Coroutines can be executed concurrently using a multi-threaded dispatcher like the default [CommonPool]. It presents
Roman Elizarovf5bc0472017-02-22 11:38:13 +03001647all the usual concurrency problems. The main problem being synchronization of access to **shared mutable state**.
1648Some solutions to this problem in the land of coroutines are similar to the solutions in the multi-threaded world,
1649but others are unique.
1650
1651### The problem
1652
Roman Elizarov1e459602017-02-27 11:05:17 +03001653Let us launch a thousand coroutines all doing the same action thousand times (for a total of a million executions).
1654We'll also measure their completion time for further comparisons:
Roman Elizarovf5bc0472017-02-22 11:38:13 +03001655
Roman Elizarov43e90112017-05-10 11:25:20 +03001656<!--- INCLUDE .*/example-sync-([0-9a-z]+).kt
Roman Elizarov1e459602017-02-27 11:05:17 +03001657import kotlin.coroutines.experimental.CoroutineContext
Roman Elizarovf5bc0472017-02-22 11:38:13 +03001658import kotlin.system.measureTimeMillis
1659-->
1660
Roman Elizarov1e459602017-02-27 11:05:17 +03001661<!--- INCLUDE .*/example-sync-03.kt
Roman Elizarovf5bc0472017-02-22 11:38:13 +03001662import java.util.concurrent.atomic.AtomicInteger
1663-->
1664
Roman Elizarov1e459602017-02-27 11:05:17 +03001665<!--- INCLUDE .*/example-sync-06.kt
Roman Elizarovf5bc0472017-02-22 11:38:13 +03001666import kotlinx.coroutines.experimental.sync.Mutex
Roman Elizarov8b38fa22017-09-27 17:44:31 +03001667import kotlinx.coroutines.experimental.sync.withLock
Roman Elizarovf5bc0472017-02-22 11:38:13 +03001668-->
1669
Roman Elizarov1e459602017-02-27 11:05:17 +03001670<!--- INCLUDE .*/example-sync-07.kt
Roman Elizarovf5bc0472017-02-22 11:38:13 +03001671import kotlinx.coroutines.experimental.channels.*
1672-->
1673
1674```kotlin
Roman Elizarov1e459602017-02-27 11:05:17 +03001675suspend fun massiveRun(context: CoroutineContext, action: suspend () -> Unit) {
1676 val n = 1000 // number of coroutines to launch
1677 val k = 1000 // times an action is repeated by each coroutine
Roman Elizarovf5bc0472017-02-22 11:38:13 +03001678 val time = measureTimeMillis {
1679 val jobs = List(n) {
Roman Elizarov1e459602017-02-27 11:05:17 +03001680 launch(context) {
1681 repeat(k) { action() }
Roman Elizarovf5bc0472017-02-22 11:38:13 +03001682 }
1683 }
1684 jobs.forEach { it.join() }
1685 }
Roman Elizarov1e459602017-02-27 11:05:17 +03001686 println("Completed ${n * k} actions in $time ms")
Roman Elizarovf5bc0472017-02-22 11:38:13 +03001687}
1688```
1689
Roman Elizarov43e90112017-05-10 11:25:20 +03001690<!--- INCLUDE .*/example-sync-([0-9a-z]+).kt -->
Roman Elizarovf5bc0472017-02-22 11:38:13 +03001691
Roman Elizarov1e459602017-02-27 11:05:17 +03001692We start with a very simple action that increments a shared mutable variable using
1693multi-threaded [CommonPool] context.
Roman Elizarovf5bc0472017-02-22 11:38:13 +03001694
1695```kotlin
1696var counter = 0
1697
1698fun main(args: Array<String>) = runBlocking<Unit> {
Roman Elizarov1e459602017-02-27 11:05:17 +03001699 massiveRun(CommonPool) {
Roman Elizarovf5bc0472017-02-22 11:38:13 +03001700 counter++
1701 }
1702 println("Counter = $counter")
1703}
1704```
1705
Roman Elizarove8d79342017-08-29 15:21:21 +03001706> You can get full code [here](core/kotlinx-coroutines-core/src/test/kotlin/guide/example-sync-01.kt)
Roman Elizarovf5bc0472017-02-22 11:38:13 +03001707
Roman Elizarov1e459602017-02-27 11:05:17 +03001708<!--- TEST LINES_START
1709Completed 1000000 actions in
1710Counter =
1711-->
Roman Elizarov731f0ad2017-02-22 20:48:45 +03001712
Roman Elizarov1e459602017-02-27 11:05:17 +03001713What does it print at the end? It is highly unlikely to ever print "Counter = 1000000", because a thousand coroutines
1714increment the `counter` concurrently from multiple threads without any synchronization.
1715
Roman Elizarov43e90112017-05-10 11:25:20 +03001716> Note: if you have an old system with 2 or fewer CPUs, then you _will_ consistently see 1000000, because
1717`CommonPool` is running in only one thread in this case. To reproduce the problem you'll need to make the
1718following change:
1719
1720```kotlin
1721val mtContext = newFixedThreadPoolContext(2, "mtPool") // explicitly define context with two threads
1722var counter = 0
1723
1724fun main(args: Array<String>) = runBlocking<Unit> {
1725 massiveRun(mtContext) { // use it instead of CommonPool in this sample and below
1726 counter++
1727 }
1728 println("Counter = $counter")
1729}
1730```
1731
Roman Elizarove8d79342017-08-29 15:21:21 +03001732> You can get full code [here](core/kotlinx-coroutines-core/src/test/kotlin/guide/example-sync-01b.kt)
Roman Elizarov43e90112017-05-10 11:25:20 +03001733
1734<!--- TEST LINES_START
1735Completed 1000000 actions in
1736Counter =
1737-->
1738
Roman Elizarov1e459602017-02-27 11:05:17 +03001739### Volatiles are of no help
1740
1741There is common misconception that making a variable `volatile` solves concurrency problem. Let us try it:
1742
1743```kotlin
1744@Volatile // in Kotlin `volatile` is an annotation
1745var counter = 0
1746
1747fun main(args: Array<String>) = runBlocking<Unit> {
1748 massiveRun(CommonPool) {
1749 counter++
1750 }
1751 println("Counter = $counter")
1752}
1753```
1754
Roman Elizarove8d79342017-08-29 15:21:21 +03001755> You can get full code [here](core/kotlinx-coroutines-core/src/test/kotlin/guide/example-sync-02.kt)
Roman Elizarov1e459602017-02-27 11:05:17 +03001756
1757<!--- TEST LINES_START
1758Completed 1000000 actions in
1759Counter =
1760-->
1761
1762This code works slower, but we still don't get "Counter = 1000000" at the end, because volatile variables guarantee
1763linearizable (this is a technical term for "atomic") reads and writes to the corresponding variable, but
1764do not provide atomicity of larger actions (increment in our case).
Roman Elizarovf5bc0472017-02-22 11:38:13 +03001765
1766### Thread-safe data structures
1767
1768The general solution that works both for threads and for coroutines is to use a thread-safe (aka synchronized,
1769linearizable, or atomic) data structure that provides all the necessarily synchronization for the corresponding
1770operations that needs to be performed on a shared state.
Roman Elizarov1e459602017-02-27 11:05:17 +03001771In the case of a simple counter we can use `AtomicInteger` class which has atomic `incrementAndGet` operations:
Roman Elizarovf5bc0472017-02-22 11:38:13 +03001772
1773```kotlin
1774var counter = AtomicInteger()
1775
1776fun main(args: Array<String>) = runBlocking<Unit> {
Roman Elizarov1e459602017-02-27 11:05:17 +03001777 massiveRun(CommonPool) {
Roman Elizarovf5bc0472017-02-22 11:38:13 +03001778 counter.incrementAndGet()
1779 }
1780 println("Counter = ${counter.get()}")
1781}
1782```
1783
Roman Elizarove8d79342017-08-29 15:21:21 +03001784> You can get full code [here](core/kotlinx-coroutines-core/src/test/kotlin/guide/example-sync-03.kt)
Roman Elizarovf5bc0472017-02-22 11:38:13 +03001785
Roman Elizarov1e459602017-02-27 11:05:17 +03001786<!--- TEST ARBITRARY_TIME
1787Completed 1000000 actions in xxx ms
1788Counter = 1000000
1789-->
Roman Elizarov731f0ad2017-02-22 20:48:45 +03001790
Roman Elizarovf5bc0472017-02-22 11:38:13 +03001791This is the fastest solution for this particular problem. It works for plain counters, collections, queues and other
1792standard data structures and basic operations on them. However, it does not easily scale to complex
1793state or to complex operations that do not have ready-to-use thread-safe implementations.
1794
Roman Elizarov1e459602017-02-27 11:05:17 +03001795### Thread confinement fine-grained
Roman Elizarovf5bc0472017-02-22 11:38:13 +03001796
Roman Elizarov1e459602017-02-27 11:05:17 +03001797_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 +03001798state is confined to a single thread. It is typically used in UI applications, where all UI state is confined to
1799the single event-dispatch/application thread. It is easy to apply with coroutines by using a
1800single-threaded context:
1801
1802```kotlin
1803val counterContext = newSingleThreadContext("CounterContext")
1804var counter = 0
1805
1806fun main(args: Array<String>) = runBlocking<Unit> {
Roman Elizarov1e459602017-02-27 11:05:17 +03001807 massiveRun(CommonPool) { // run each coroutine in CommonPool
1808 run(counterContext) { // but confine each increment to the single-threaded context
Roman Elizarovf5bc0472017-02-22 11:38:13 +03001809 counter++
1810 }
1811 }
1812 println("Counter = $counter")
1813}
1814```
1815
Roman Elizarove8d79342017-08-29 15:21:21 +03001816> You can get full code [here](core/kotlinx-coroutines-core/src/test/kotlin/guide/example-sync-04.kt)
Roman Elizarovf5bc0472017-02-22 11:38:13 +03001817
Roman Elizarov1e459602017-02-27 11:05:17 +03001818<!--- TEST ARBITRARY_TIME
1819Completed 1000000 actions in xxx ms
1820Counter = 1000000
1821-->
1822
1823This code works very slowly, because it does _fine-grained_ thread-confinement. Each individual increment switches
1824from multi-threaded `CommonPool` context to the single-threaded context using [run] block.
1825
1826### Thread confinement coarse-grained
1827
1828In practice, thread confinement is performed in large chunks, e.g. big pieces of state-updating business logic
1829are confined to the single thread. The following example does it like that, running each coroutine in
1830the single-threaded context to start with.
1831
1832```kotlin
1833val counterContext = newSingleThreadContext("CounterContext")
1834var counter = 0
1835
1836fun main(args: Array<String>) = runBlocking<Unit> {
1837 massiveRun(counterContext) { // run each coroutine in the single-threaded context
1838 counter++
1839 }
1840 println("Counter = $counter")
1841}
1842```
1843
Roman Elizarove8d79342017-08-29 15:21:21 +03001844> You can get full code [here](core/kotlinx-coroutines-core/src/test/kotlin/guide/example-sync-05.kt)
Roman Elizarov1e459602017-02-27 11:05:17 +03001845
1846<!--- TEST ARBITRARY_TIME
1847Completed 1000000 actions in xxx ms
1848Counter = 1000000
1849-->
1850
1851This now works much faster and produces correct result.
Roman Elizarov731f0ad2017-02-22 20:48:45 +03001852
Roman Elizarovf5bc0472017-02-22 11:38:13 +03001853### Mutual exclusion
1854
1855Mutual exclusion solution to the problem is to protect all modifications of the shared state with a _critical section_
1856that is never executed concurrently. In a blocking world you'd typically use `synchronized` or `ReentrantLock` for that.
1857Coroutine's alternative is called [Mutex]. It has [lock][Mutex.lock] and [unlock][Mutex.unlock] functions to
1858delimit a critical section. The key difference is that `Mutex.lock` is a suspending function. It does not block a thread.
1859
Roman Elizarov88396732017-09-27 21:30:47 +03001860There is also [withLock] extension function that conveniently represents
Roman Elizarov8b38fa22017-09-27 17:44:31 +03001861`mutex.lock(); try { ... } finally { mutex.unlock() }` pattern:
1862
Roman Elizarovf5bc0472017-02-22 11:38:13 +03001863```kotlin
1864val mutex = Mutex()
1865var counter = 0
1866
1867fun main(args: Array<String>) = runBlocking<Unit> {
Roman Elizarov1e459602017-02-27 11:05:17 +03001868 massiveRun(CommonPool) {
Roman Elizarov8b38fa22017-09-27 17:44:31 +03001869 mutex.withLock {
1870 counter++
1871 }
Roman Elizarovf5bc0472017-02-22 11:38:13 +03001872 }
1873 println("Counter = $counter")
1874}
1875```
1876
Roman Elizarove8d79342017-08-29 15:21:21 +03001877> You can get full code [here](core/kotlinx-coroutines-core/src/test/kotlin/guide/example-sync-06.kt)
Roman Elizarovf5bc0472017-02-22 11:38:13 +03001878
Roman Elizarov1e459602017-02-27 11:05:17 +03001879<!--- TEST ARBITRARY_TIME
1880Completed 1000000 actions in xxx ms
1881Counter = 1000000
1882-->
1883
1884The locking in this example is fine-grained, so it pays the price. However, it is a good choice for some situations
1885where you absolutely must modify some shared state periodically, but there is no natural thread that this state
1886is confined to.
Roman Elizarov731f0ad2017-02-22 20:48:45 +03001887
Roman Elizarovf5bc0472017-02-22 11:38:13 +03001888### Actors
1889
1890An actor is a combination of a coroutine, the state that is confined and is encapsulated into this coroutine,
1891and a channel to communicate with other coroutines. A simple actor can be written as a function,
1892but an actor with a complex state is better suited for a class.
1893
Roman Elizarovc0e19f82017-02-27 11:59:14 +03001894There is an [actor] coroutine builder that conveniently combines actor's mailbox channel into its
1895scope to receive messages from and combines the send channel into the resulting job object, so that a
1896single reference to the actor can be carried around as its handle.
1897
Roman Elizarov256812a2017-07-22 01:00:30 +03001898The first step of using an actor is to define a class of messages that an actor is going to process.
1899Kotlin's [sealed classes](https://kotlinlang.org/docs/reference/sealed-classes.html) are well suited for that purpose.
1900We define `CounterMsg` sealed class with `IncCounter` message to increment a counter and `GetCounter` message
1901to get its value. The later needs to send a response. A [CompletableDeferred] communication
1902primitive, that represents a single value that will be known (communicated) in the future,
1903is used here for that purpose.
1904
Roman Elizarovf5bc0472017-02-22 11:38:13 +03001905```kotlin
1906// Message types for counterActor
1907sealed class CounterMsg
1908object IncCounter : CounterMsg() // one-way message to increment counter
Roman Elizarov256812a2017-07-22 01:00:30 +03001909class GetCounter(val response: CompletableDeferred<Int>) : CounterMsg() // a request with reply
1910```
Roman Elizarovf5bc0472017-02-22 11:38:13 +03001911
Roman Elizarov256812a2017-07-22 01:00:30 +03001912Then we define a function that launches an actor using an [actor] coroutine builder:
1913
1914```kotlin
Roman Elizarovf5bc0472017-02-22 11:38:13 +03001915// This function launches a new counter actor
Roman Elizarov66f018c2017-09-29 21:39:03 +03001916fun counterActor() = actor<CounterMsg> {
Roman Elizarovf5bc0472017-02-22 11:38:13 +03001917 var counter = 0 // actor state
Roman Elizarovc0e19f82017-02-27 11:59:14 +03001918 for (msg in channel) { // iterate over incoming messages
Roman Elizarovf5bc0472017-02-22 11:38:13 +03001919 when (msg) {
1920 is IncCounter -> counter++
Roman Elizarov256812a2017-07-22 01:00:30 +03001921 is GetCounter -> msg.response.complete(counter)
Roman Elizarovf5bc0472017-02-22 11:38:13 +03001922 }
1923 }
1924}
Roman Elizarov256812a2017-07-22 01:00:30 +03001925```
Roman Elizarovf5bc0472017-02-22 11:38:13 +03001926
Roman Elizarov256812a2017-07-22 01:00:30 +03001927The main code is straightforward:
1928
1929```kotlin
Roman Elizarovf5bc0472017-02-22 11:38:13 +03001930fun main(args: Array<String>) = runBlocking<Unit> {
Roman Elizarovc0e19f82017-02-27 11:59:14 +03001931 val counter = counterActor() // create the actor
Roman Elizarov1e459602017-02-27 11:05:17 +03001932 massiveRun(CommonPool) {
Roman Elizarovc0e19f82017-02-27 11:59:14 +03001933 counter.send(IncCounter)
Roman Elizarovf5bc0472017-02-22 11:38:13 +03001934 }
Roman Elizarov256812a2017-07-22 01:00:30 +03001935 // send a message to get a counter value from an actor
1936 val response = CompletableDeferred<Int>()
Roman Elizarovc0e19f82017-02-27 11:59:14 +03001937 counter.send(GetCounter(response))
Roman Elizarov256812a2017-07-22 01:00:30 +03001938 println("Counter = ${response.await()}")
Roman Elizarovc0e19f82017-02-27 11:59:14 +03001939 counter.close() // shutdown the actor
Roman Elizarovf5bc0472017-02-22 11:38:13 +03001940}
1941```
1942
Roman Elizarove8d79342017-08-29 15:21:21 +03001943> You can get full code [here](core/kotlinx-coroutines-core/src/test/kotlin/guide/example-sync-07.kt)
Roman Elizarovf5bc0472017-02-22 11:38:13 +03001944
Roman Elizarov1e459602017-02-27 11:05:17 +03001945<!--- TEST ARBITRARY_TIME
1946Completed 1000000 actions in xxx ms
1947Counter = 1000000
1948-->
Roman Elizarov731f0ad2017-02-22 20:48:45 +03001949
Roman Elizarovc0e19f82017-02-27 11:59:14 +03001950It does not matter (for correctness) what context the actor itself is executed in. An actor is
Roman Elizarovf5bc0472017-02-22 11:38:13 +03001951a coroutine and a coroutine is executed sequentially, so confinement of the state to the specific coroutine
1952works as a solution to the problem of shared mutable state.
1953
Roman Elizarovc0e19f82017-02-27 11:59:14 +03001954Actor is more efficient than locking under load, because in this case it always has work to do and it does not
1955have to switch to a different context at all.
1956
1957> Note, that an [actor] coroutine builder is a dual of [produce] coroutine builder. An actor is associated
1958 with the channel that it receives messages from, while a producer is associated with the channel that it
1959 sends elements to.
Roman Elizarov1e459602017-02-27 11:05:17 +03001960
Roman Elizarovd4dcbe22017-02-22 09:57:46 +03001961## Select expression
1962
Roman Elizarova84730b2017-02-22 11:58:50 +03001963Select expression makes it possible to await multiple suspending functions simultaneously and _select_
Roman Elizarovd4dcbe22017-02-22 09:57:46 +03001964the first one that becomes available.
1965
1966<!--- INCLUDE .*/example-select-([0-9]+).kt
1967import kotlinx.coroutines.experimental.channels.*
1968import kotlinx.coroutines.experimental.selects.*
1969-->
1970
1971### Selecting from channels
1972
Roman Elizarov57857202017-03-02 23:17:25 +03001973Let us have two producers of strings: `fizz` and `buzz`. The `fizz` produces "Fizz" string every 300 ms:
1974
1975<!--- INCLUDE .*/example-select-01.kt
1976import kotlin.coroutines.experimental.CoroutineContext
1977-->
1978
Roman Elizarovd4dcbe22017-02-22 09:57:46 +03001979```kotlin
Roman Elizarov57857202017-03-02 23:17:25 +03001980fun fizz(context: CoroutineContext) = produce<String>(context) {
1981 while (true) { // sends "Fizz" every 300 ms
Roman Elizarovd4dcbe22017-02-22 09:57:46 +03001982 delay(300)
1983 send("Fizz")
1984 }
1985}
1986```
1987
Roman Elizarov57857202017-03-02 23:17:25 +03001988And the `buzz` produces "Buzz!" string every 500 ms:
Roman Elizarovd4dcbe22017-02-22 09:57:46 +03001989
1990```kotlin
Roman Elizarov57857202017-03-02 23:17:25 +03001991fun buzz(context: CoroutineContext) = produce<String>(context) {
1992 while (true) { // sends "Buzz!" every 500 ms
Roman Elizarovd4dcbe22017-02-22 09:57:46 +03001993 delay(500)
1994 send("Buzz!")
1995 }
1996}
1997```
1998
1999Using [receive][ReceiveChannel.receive] suspending function we can receive _either_ from one channel or the
2000other. But [select] expression allows us to receive from _both_ simultaneously using its
Roman Elizarov8a5564d2017-09-06 18:48:22 +03002001[onReceive][ReceiveChannel.onReceive] clauses:
Roman Elizarovd4dcbe22017-02-22 09:57:46 +03002002
2003```kotlin
Roman Elizarov57857202017-03-02 23:17:25 +03002004suspend fun selectFizzBuzz(fizz: ReceiveChannel<String>, buzz: ReceiveChannel<String>) {
Roman Elizarovd4dcbe22017-02-22 09:57:46 +03002005 select<Unit> { // <Unit> means that this select expression does not produce any result
2006 fizz.onReceive { value -> // this is the first select clause
2007 println("fizz -> '$value'")
2008 }
2009 buzz.onReceive { value -> // this is the second select clause
2010 println("buzz -> '$value'")
2011 }
2012 }
2013}
2014```
2015
Roman Elizarov57857202017-03-02 23:17:25 +03002016Let us run it all seven times:
Roman Elizarovd4dcbe22017-02-22 09:57:46 +03002017
2018```kotlin
2019fun main(args: Array<String>) = runBlocking<Unit> {
Roman Elizarov43e3af72017-07-21 16:01:31 +03002020 val fizz = fizz(coroutineContext)
2021 val buzz = buzz(coroutineContext)
Roman Elizarovd4dcbe22017-02-22 09:57:46 +03002022 repeat(7) {
Roman Elizarov57857202017-03-02 23:17:25 +03002023 selectFizzBuzz(fizz, buzz)
Roman Elizarovd4dcbe22017-02-22 09:57:46 +03002024 }
Roman Elizarov8b38fa22017-09-27 17:44:31 +03002025 coroutineContext.cancelChildren() // cancel fizz & buzz coroutines
Roman Elizarovd4dcbe22017-02-22 09:57:46 +03002026}
2027```
2028
Roman Elizarove8d79342017-08-29 15:21:21 +03002029> You can get full code [here](core/kotlinx-coroutines-core/src/test/kotlin/guide/example-select-01.kt)
Roman Elizarovd4dcbe22017-02-22 09:57:46 +03002030
2031The result of this code is:
2032
Roman Elizarov731f0ad2017-02-22 20:48:45 +03002033```text
Roman Elizarovd4dcbe22017-02-22 09:57:46 +03002034fizz -> 'Fizz'
2035buzz -> 'Buzz!'
2036fizz -> 'Fizz'
2037fizz -> 'Fizz'
2038buzz -> 'Buzz!'
2039fizz -> 'Fizz'
2040buzz -> 'Buzz!'
2041```
2042
Roman Elizarov731f0ad2017-02-22 20:48:45 +03002043<!--- TEST -->
2044
Roman Elizarovd4dcbe22017-02-22 09:57:46 +03002045### Selecting on close
2046
Roman Elizarov8a5564d2017-09-06 18:48:22 +03002047The [onReceive][ReceiveChannel.onReceive] clause in `select` fails when the channel is closed and the corresponding
2048`select` throws an exception. We can use [onReceiveOrNull][ReceiveChannel.onReceiveOrNull] clause to perform a
Roman Elizarova84730b2017-02-22 11:58:50 +03002049specific 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 +03002050the result of its selected clause:
2051
2052```kotlin
2053suspend fun selectAorB(a: ReceiveChannel<String>, b: ReceiveChannel<String>): String =
2054 select<String> {
2055 a.onReceiveOrNull { value ->
2056 if (value == null)
2057 "Channel 'a' is closed"
2058 else
2059 "a -> '$value'"
2060 }
2061 b.onReceiveOrNull { value ->
2062 if (value == null)
2063 "Channel 'b' is closed"
2064 else
2065 "b -> '$value'"
2066 }
2067 }
2068```
2069
Roman Elizarova84730b2017-02-22 11:58:50 +03002070Let's use it with channel `a` that produces "Hello" string four times and
2071channel `b` that produces "World" four times:
Roman Elizarovd4dcbe22017-02-22 09:57:46 +03002072
2073```kotlin
2074fun main(args: Array<String>) = runBlocking<Unit> {
2075 // we are using the context of the main thread in this example for predictability ...
Roman Elizarov43e3af72017-07-21 16:01:31 +03002076 val a = produce<String>(coroutineContext) {
Roman Elizarova84730b2017-02-22 11:58:50 +03002077 repeat(4) { send("Hello $it") }
Roman Elizarovd4dcbe22017-02-22 09:57:46 +03002078 }
Roman Elizarov43e3af72017-07-21 16:01:31 +03002079 val b = produce<String>(coroutineContext) {
Roman Elizarova84730b2017-02-22 11:58:50 +03002080 repeat(4) { send("World $it") }
Roman Elizarovd4dcbe22017-02-22 09:57:46 +03002081 }
2082 repeat(8) { // print first eight results
2083 println(selectAorB(a, b))
2084 }
Roman Elizarov8b38fa22017-09-27 17:44:31 +03002085 coroutineContext.cancelChildren()
Roman Elizarovd4dcbe22017-02-22 09:57:46 +03002086}
2087```
2088
Roman Elizarove8d79342017-08-29 15:21:21 +03002089> You can get full code [here](core/kotlinx-coroutines-core/src/test/kotlin/guide/example-select-02.kt)
Roman Elizarovd4dcbe22017-02-22 09:57:46 +03002090
Roman Elizarova84730b2017-02-22 11:58:50 +03002091The result of this code is quite interesting, so we'll analyze it in mode detail:
Roman Elizarovd4dcbe22017-02-22 09:57:46 +03002092
Roman Elizarov731f0ad2017-02-22 20:48:45 +03002093```text
Roman Elizarovd4dcbe22017-02-22 09:57:46 +03002094a -> 'Hello 0'
2095a -> 'Hello 1'
2096b -> 'World 0'
2097a -> 'Hello 2'
2098a -> 'Hello 3'
2099b -> 'World 1'
2100Channel 'a' is closed
2101Channel 'a' is closed
2102```
2103
Roman Elizarov731f0ad2017-02-22 20:48:45 +03002104<!--- TEST -->
2105
Roman Elizarova84730b2017-02-22 11:58:50 +03002106There are couple of observations to make out of it.
Roman Elizarovd4dcbe22017-02-22 09:57:46 +03002107
2108First of all, `select` is _biased_ to the first clause. When several clauses are selectable at the same time,
2109the first one among them gets selected. Here, both channels are constantly producing strings, so `a` channel,
Roman Elizarova84730b2017-02-22 11:58:50 +03002110being 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 +03002111time to time on its [send][SendChannel.send] invocation and gives a chance for `b` to send, too.
2112
Roman Elizarov8a5564d2017-09-06 18:48:22 +03002113The second observation, is that [onReceiveOrNull][ReceiveChannel.onReceiveOrNull] gets immediately selected when the
Roman Elizarovd4dcbe22017-02-22 09:57:46 +03002114channel is already closed.
2115
2116### Selecting to send
2117
Roman Elizarov8a5564d2017-09-06 18:48:22 +03002118Select expression has [onSend][SendChannel.onSend] clause that can be used for a great good in combination
Roman Elizarovd4dcbe22017-02-22 09:57:46 +03002119with a biased nature of selection.
2120
Roman Elizarova84730b2017-02-22 11:58:50 +03002121Let us write an example of producer of integers that sends its values to a `side` channel when
Roman Elizarovd4dcbe22017-02-22 09:57:46 +03002122the consumers on its primary channel cannot keep up with it:
2123
Roman Elizarov8b38fa22017-09-27 17:44:31 +03002124<!--- INCLUDE
2125import kotlin.coroutines.experimental.CoroutineContext
2126-->
2127
Roman Elizarovd4dcbe22017-02-22 09:57:46 +03002128```kotlin
Roman Elizarov8b38fa22017-09-27 17:44:31 +03002129fun produceNumbers(context: CoroutineContext, side: SendChannel<Int>) = produce<Int>(context) {
Roman Elizarovd4dcbe22017-02-22 09:57:46 +03002130 for (num in 1..10) { // produce 10 numbers from 1 to 10
2131 delay(100) // every 100 ms
2132 select<Unit> {
Roman Elizarova84730b2017-02-22 11:58:50 +03002133 onSend(num) {} // Send to the primary channel
2134 side.onSend(num) {} // or to the side channel
Roman Elizarovd4dcbe22017-02-22 09:57:46 +03002135 }
2136 }
2137}
2138```
2139
2140Consumer is going to be quite slow, taking 250 ms to process each number:
2141
2142```kotlin
2143fun main(args: Array<String>) = runBlocking<Unit> {
2144 val side = Channel<Int>() // allocate side channel
Roman Elizarov43e3af72017-07-21 16:01:31 +03002145 launch(coroutineContext) { // this is a very fast consumer for the side channel
Roman Elizarov86349be2017-03-17 16:47:37 +03002146 side.consumeEach { println("Side channel has $it") }
Roman Elizarovd4dcbe22017-02-22 09:57:46 +03002147 }
Roman Elizarov8b38fa22017-09-27 17:44:31 +03002148 produceNumbers(coroutineContext, side).consumeEach {
Roman Elizarov86349be2017-03-17 16:47:37 +03002149 println("Consuming $it")
Roman Elizarovd4dcbe22017-02-22 09:57:46 +03002150 delay(250) // let us digest the consumed number properly, do not hurry
2151 }
2152 println("Done consuming")
Roman Elizarov8b38fa22017-09-27 17:44:31 +03002153 coroutineContext.cancelChildren()
Roman Elizarovd4dcbe22017-02-22 09:57:46 +03002154}
2155```
2156
Roman Elizarove8d79342017-08-29 15:21:21 +03002157> You can get full code [here](core/kotlinx-coroutines-core/src/test/kotlin/guide/example-select-03.kt)
Roman Elizarovd4dcbe22017-02-22 09:57:46 +03002158
2159So let us see what happens:
2160
Roman Elizarov731f0ad2017-02-22 20:48:45 +03002161```text
Roman Elizarovd4dcbe22017-02-22 09:57:46 +03002162Consuming 1
2163Side channel has 2
2164Side channel has 3
2165Consuming 4
2166Side channel has 5
2167Side channel has 6
2168Consuming 7
2169Side channel has 8
2170Side channel has 9
2171Consuming 10
2172Done consuming
2173```
2174
Roman Elizarov731f0ad2017-02-22 20:48:45 +03002175<!--- TEST -->
2176
Roman Elizarovd4dcbe22017-02-22 09:57:46 +03002177### Selecting deferred values
2178
Roman Elizarov8a5564d2017-09-06 18:48:22 +03002179Deferred values can be selected using [onAwait][Deferred.onAwait] clause.
Roman Elizarova84730b2017-02-22 11:58:50 +03002180Let us start with an async function that returns a deferred string value after
Roman Elizarovd4dcbe22017-02-22 09:57:46 +03002181a random delay:
2182
2183<!--- INCLUDE .*/example-select-04.kt
2184import java.util.*
2185-->
2186
2187```kotlin
Roman Elizarov66f018c2017-09-29 21:39:03 +03002188fun asyncString(time: Int) = async {
Roman Elizarovd4dcbe22017-02-22 09:57:46 +03002189 delay(time.toLong())
2190 "Waited for $time ms"
2191}
2192```
2193
Roman Elizarova84730b2017-02-22 11:58:50 +03002194Let us start a dozen of them with a random delay.
Roman Elizarovd4dcbe22017-02-22 09:57:46 +03002195
2196```kotlin
2197fun asyncStringsList(): List<Deferred<String>> {
2198 val random = Random(3)
Roman Elizarova84730b2017-02-22 11:58:50 +03002199 return List(12) { asyncString(random.nextInt(1000)) }
Roman Elizarovd4dcbe22017-02-22 09:57:46 +03002200}
2201```
2202
Roman Elizarova84730b2017-02-22 11:58:50 +03002203Now 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 +03002204that 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 +03002205so we can provide clauses for it using an arbitrary code. In this case we iterate over a list
2206of deferred values to provide `onAwait` clause for each deferred value.
Roman Elizarovd4dcbe22017-02-22 09:57:46 +03002207
2208```kotlin
2209fun main(args: Array<String>) = runBlocking<Unit> {
2210 val list = asyncStringsList()
2211 val result = select<String> {
2212 list.withIndex().forEach { (index, deferred) ->
2213 deferred.onAwait { answer ->
2214 "Deferred $index produced answer '$answer'"
2215 }
2216 }
2217 }
2218 println(result)
Roman Elizarov7c864d82017-02-27 10:17:50 +03002219 val countActive = list.count { it.isActive }
Roman Elizarovd4dcbe22017-02-22 09:57:46 +03002220 println("$countActive coroutines are still active")
2221}
2222```
2223
Roman Elizarove8d79342017-08-29 15:21:21 +03002224> You can get full code [here](core/kotlinx-coroutines-core/src/test/kotlin/guide/example-select-04.kt)
Roman Elizarovd4dcbe22017-02-22 09:57:46 +03002225
2226The output is:
2227
Roman Elizarov731f0ad2017-02-22 20:48:45 +03002228```text
Roman Elizarova84730b2017-02-22 11:58:50 +03002229Deferred 4 produced answer 'Waited for 128 ms'
Roman Elizarovd4dcbe22017-02-22 09:57:46 +0300223011 coroutines are still active
2231```
2232
Roman Elizarov731f0ad2017-02-22 20:48:45 +03002233<!--- TEST -->
2234
Roman Elizarovd4dcbe22017-02-22 09:57:46 +03002235### Switch over a channel of deferred values
2236
Roman Elizarova84730b2017-02-22 11:58:50 +03002237Let us write a channel producer function that consumes a channel of deferred string values, waits for each received
2238deferred 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 +03002239[onReceiveOrNull][ReceiveChannel.onReceiveOrNull] and [onAwait][Deferred.onAwait] clauses in the same `select`:
Roman Elizarovd4dcbe22017-02-22 09:57:46 +03002240
2241```kotlin
Roman Elizarov66f018c2017-09-29 21:39:03 +03002242fun switchMapDeferreds(input: ReceiveChannel<Deferred<String>>) = produce<String> {
Roman Elizarova84730b2017-02-22 11:58:50 +03002243 var current = input.receive() // start with first received deferred value
Roman Elizarovd4dcbe22017-02-22 09:57:46 +03002244 while (isActive) { // loop while not cancelled/closed
2245 val next = select<Deferred<String>?> { // return next deferred value from this select or null
2246 input.onReceiveOrNull { update ->
2247 update // replaces next value to wait
2248 }
2249 current.onAwait { value ->
2250 send(value) // send value that current deferred has produced
2251 input.receiveOrNull() // and use the next deferred from the input channel
2252 }
2253 }
2254 if (next == null) {
2255 println("Channel was closed")
2256 break // out of loop
2257 } else {
2258 current = next
2259 }
2260 }
2261}
2262```
2263
2264To test it, we'll use a simple async function that resolves to a specified string after a specified time:
2265
2266```kotlin
Roman Elizarov66f018c2017-09-29 21:39:03 +03002267fun asyncString(str: String, time: Long) = async {
Roman Elizarovd4dcbe22017-02-22 09:57:46 +03002268 delay(time)
2269 str
2270}
2271```
2272
2273The main function just launches a coroutine to print results of `switchMapDeferreds` and sends some test
2274data to it:
2275
2276```kotlin
2277fun main(args: Array<String>) = runBlocking<Unit> {
2278 val chan = Channel<Deferred<String>>() // the channel for test
Roman Elizarov43e3af72017-07-21 16:01:31 +03002279 launch(coroutineContext) { // launch printing coroutine
Roman Elizarovd4dcbe22017-02-22 09:57:46 +03002280 for (s in switchMapDeferreds(chan))
2281 println(s) // print each received string
2282 }
2283 chan.send(asyncString("BEGIN", 100))
2284 delay(200) // enough time for "BEGIN" to be produced
2285 chan.send(asyncString("Slow", 500))
Roman Elizarova84730b2017-02-22 11:58:50 +03002286 delay(100) // not enough time to produce slow
Roman Elizarovd4dcbe22017-02-22 09:57:46 +03002287 chan.send(asyncString("Replace", 100))
Roman Elizarova84730b2017-02-22 11:58:50 +03002288 delay(500) // give it time before the last one
Roman Elizarovd4dcbe22017-02-22 09:57:46 +03002289 chan.send(asyncString("END", 500))
2290 delay(1000) // give it time to process
Roman Elizarova84730b2017-02-22 11:58:50 +03002291 chan.close() // close the channel ...
Roman Elizarovd4dcbe22017-02-22 09:57:46 +03002292 delay(500) // and wait some time to let it finish
2293}
2294```
2295
Roman Elizarove8d79342017-08-29 15:21:21 +03002296> You can get full code [here](core/kotlinx-coroutines-core/src/test/kotlin/guide/example-select-05.kt)
Roman Elizarovd4dcbe22017-02-22 09:57:46 +03002297
2298The result of this code:
2299
Roman Elizarov731f0ad2017-02-22 20:48:45 +03002300```text
Roman Elizarovd4dcbe22017-02-22 09:57:46 +03002301BEGIN
2302Replace
2303END
2304Channel was closed
2305```
2306
Roman Elizarov731f0ad2017-02-22 20:48:45 +03002307<!--- TEST -->
Roman Elizarovd4dcbe22017-02-22 09:57:46 +03002308
Roman Elizarov8db17332017-03-09 12:40:45 +03002309## Further reading
2310
2311* [Guide to UI programming with coroutines](ui/coroutines-guide-ui.md)
Roman Elizarov8a4a8e12017-03-09 19:52:58 +03002312* [Guide to reactive streams with coroutines](reactive/coroutines-guide-reactive.md)
Roman Elizarov8db17332017-03-09 12:40:45 +03002313* [Coroutines design document (KEEP)](https://github.com/Kotlin/kotlin-coroutines/blob/master/kotlin-coroutines-informal.md)
2314* [Full kotlinx.coroutines API reference](http://kotlin.github.io/kotlinx.coroutines)
2315
Roman Elizarove7e2ad12017-05-17 14:47:31 +03002316<!--- MODULE kotlinx-coroutines-core -->
Roman Elizarove0c817d2017-02-10 10:22:01 +03002317<!--- INDEX kotlinx.coroutines.experimental -->
Roman Elizarovd4dcbe22017-02-22 09:57:46 +03002318[launch]: https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines.experimental/launch.html
2319[delay]: https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines.experimental/delay.html
2320[runBlocking]: https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines.experimental/run-blocking.html
Roman Elizarove82dee72017-08-18 16:49:09 +03002321[Job]: https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines.experimental/-job/index.html
Roman Elizarov8b38fa22017-09-27 17:44:31 +03002322[cancelAndJoin]: https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines.experimental/cancel-and-join.html
Roman Elizarov88396732017-09-27 21:30:47 +03002323[Job.cancel]: https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines.experimental/-job/cancel.html
2324[Job.join]: https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines.experimental/-job/join.html
Roman Elizarovd4dcbe22017-02-22 09:57:46 +03002325[CancellationException]: https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines.experimental/-cancellation-exception.html
2326[yield]: https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines.experimental/yield.html
Roman Elizarovbff3f372017-03-01 18:12:27 +03002327[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 +03002328[CoroutineScope]: https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines.experimental/-coroutine-scope/index.html
2329[run]: https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines.experimental/run.html
2330[NonCancellable]: https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines.experimental/-non-cancellable/index.html
2331[withTimeout]: https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines.experimental/with-timeout.html
Roman Elizarov63f6ea22017-09-06 18:42:34 +03002332[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 +03002333[async]: https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines.experimental/async.html
2334[Deferred]: https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines.experimental/-deferred/index.html
Roman Elizarovecda27f2017-04-06 23:06:26 +03002335[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 +03002336[Deferred.await]: https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines.experimental/-deferred/await.html
2337[Job.start]: https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines.experimental/-job/start.html
Roman Elizarov419a6c82017-02-09 18:36:22 +03002338[CoroutineDispatcher]: https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines.experimental/-coroutine-dispatcher/index.html
Roman Elizarovd9ae2bc2017-10-20 17:36:56 +08002339[DefaultDispatcher]: https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines.experimental/-default-dispatcher.html
Roman Elizarov66f018c2017-09-29 21:39:03 +03002340[CommonPool]: https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines.experimental/-common-pool/index.html
Roman Elizarov43e3af72017-07-21 16:01:31 +03002341[CoroutineScope.coroutineContext]: https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines.experimental/-coroutine-scope/coroutine-context.html
Roman Elizarov419a6c82017-02-09 18:36:22 +03002342[Unconfined]: https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines.experimental/-unconfined/index.html
Roman Elizarovd9ae2bc2017-10-20 17:36:56 +08002343[newSingleThreadContext]: https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines.experimental/new-single-thread-context.html
2344[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 +03002345[newCoroutineContext]: https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines.experimental/new-coroutine-context.html
Roman Elizarovd4dcbe22017-02-22 09:57:46 +03002346[CoroutineName]: https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines.experimental/-coroutine-name/index.html
Roman Elizarov88396732017-09-27 21:30:47 +03002347[Job()]: https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines.experimental/-job.html
2348[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 +03002349[CompletableDeferred]: https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines.experimental/-completable-deferred/index.html
Roman Elizarov8a5564d2017-09-06 18:48:22 +03002350[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 +03002351<!--- INDEX kotlinx.coroutines.experimental.sync -->
Roman Elizarove82dee72017-08-18 16:49:09 +03002352[Mutex]: https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines.experimental.sync/-mutex/index.html
Roman Elizarovbff3f372017-03-01 18:12:27 +03002353[Mutex.lock]: https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines.experimental.sync/-mutex/lock.html
2354[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 +03002355[withLock]: https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines.experimental.sync/with-lock.html
Roman Elizarove0c817d2017-02-10 10:22:01 +03002356<!--- INDEX kotlinx.coroutines.experimental.channels -->
Roman Elizarove82dee72017-08-18 16:49:09 +03002357[Channel]: https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines.experimental.channels/-channel/index.html
Roman Elizarovbff3f372017-03-01 18:12:27 +03002358[SendChannel.send]: https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines.experimental.channels/-send-channel/send.html
2359[ReceiveChannel.receive]: https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines.experimental.channels/-receive-channel/receive.html
2360[SendChannel.close]: https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines.experimental.channels/-send-channel/close.html
Roman Elizarova5e653f2017-02-13 13:49:55 +03002361[produce]: https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines.experimental.channels/produce.html
Roman Elizarov86349be2017-03-17 16:47:37 +03002362[consumeEach]: https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines.experimental.channels/consume-each.html
Roman Elizarov88396732017-09-27 21:30:47 +03002363[Channel()]: https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines.experimental.channels/-channel.html
Roman Elizarovc0e19f82017-02-27 11:59:14 +03002364[actor]: https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines.experimental.channels/actor.html
Roman Elizarov8a5564d2017-09-06 18:48:22 +03002365[ReceiveChannel.onReceive]: https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines.experimental.channels/-receive-channel/on-receive.html
2366[ReceiveChannel.onReceiveOrNull]: https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines.experimental.channels/-receive-channel/on-receive-or-null.html
2367[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 +03002368<!--- INDEX kotlinx.coroutines.experimental.selects -->
2369[select]: https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines.experimental.selects/select.html
Roman Elizarov419a6c82017-02-09 18:36:22 +03002370<!--- END -->