blob: c83be1ac5e6ecf461098fcaa1db5283c8717069d [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
Roman Elizarova4d45d22017-11-20 16:47:09 +030035This is a guide on core features of `kotlinx.coroutines` with a series of examples.
Roman Elizarov7deefb82017-01-31 10:33:17 +030036
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 Elizarova4d45d22017-11-20 16:47:09 +030044coroutine-enabled primitives that this guide covers, including `launch`, `async` and others.
Roman Elizarov2a638922017-03-04 10:22:43 +030045You 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)
Vsevolod Tolstopyatov03d2ff72018-05-29 17:28:20 +030091 * [Ticker channels](#ticker-channels)
Roman Elizarovb0517ba2017-02-27 14:03:14 +030092 * [Channels are fair](#channels-are-fair)
Roman Elizarovf5bc0472017-02-22 11:38:13 +030093* [Shared mutable state and concurrency](#shared-mutable-state-and-concurrency)
94 * [The problem](#the-problem)
Roman Elizarov1e459602017-02-27 11:05:17 +030095 * [Volatiles are of no help](#volatiles-are-of-no-help)
Roman Elizarovf5bc0472017-02-22 11:38:13 +030096 * [Thread-safe data structures](#thread-safe-data-structures)
Roman Elizarov1e459602017-02-27 11:05:17 +030097 * [Thread confinement fine-grained](#thread-confinement-fine-grained)
98 * [Thread confinement coarse-grained](#thread-confinement-coarse-grained)
Roman Elizarovf5bc0472017-02-22 11:38:13 +030099 * [Mutual exclusion](#mutual-exclusion)
100 * [Actors](#actors)
Roman Elizarovd4dcbe22017-02-22 09:57:46 +0300101* [Select expression](#select-expression)
102 * [Selecting from channels](#selecting-from-channels)
103 * [Selecting on close](#selecting-on-close)
104 * [Selecting to send](#selecting-to-send)
105 * [Selecting deferred values](#selecting-deferred-values)
106 * [Switch over a channel of deferred values](#switch-over-a-channel-of-deferred-values)
Roman Elizarov8db17332017-03-09 12:40:45 +0300107* [Further reading](#further-reading)
Roman Elizarovfa7723e2017-02-06 11:17:51 +0300108
Roman Elizarova5e653f2017-02-13 13:49:55 +0300109<!--- END_TOC -->
Roman Elizarov1293ccd2017-02-01 18:49:54 +0300110
111## Coroutine basics
112
113This section covers basic coroutine concepts.
114
115### Your first coroutine
Roman Elizarov7deefb82017-01-31 10:33:17 +0300116
117Run the following code:
118
119```kotlin
120fun main(args: Array<String>) {
Roman Elizarova4d45d22017-11-20 16:47:09 +0300121 launch { // launch new coroutine in background and continue
Roman Elizarov7deefb82017-01-31 10:33:17 +0300122 delay(1000L) // non-blocking delay for 1 second (default time unit is ms)
123 println("World!") // print after delay
124 }
Roman Elizarova4d45d22017-11-20 16:47:09 +0300125 println("Hello,") // main thread continues while coroutine is delayed
Roman Elizarov7deefb82017-01-31 10:33:17 +0300126 Thread.sleep(2000L) // block main thread for 2 seconds to keep JVM alive
127}
128```
129
Roman Elizarove8d79342017-08-29 15:21:21 +0300130> 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 +0300131
132Run this code:
133
Roman Elizarov731f0ad2017-02-22 20:48:45 +0300134```text
Roman Elizarov7deefb82017-01-31 10:33:17 +0300135Hello,
136World!
137```
138
Roman Elizarov731f0ad2017-02-22 20:48:45 +0300139<!--- TEST -->
140
Roman Elizarov419a6c82017-02-09 18:36:22 +0300141Essentially, coroutines are light-weight threads.
142They are launched with [launch] _coroutine builder_.
143You can achieve the same result replacing
Roman Elizarov66f018c2017-09-29 21:39:03 +0300144`launch { ... }` with `thread { ... }` and `delay(...)` with `Thread.sleep(...)`. Try it.
Roman Elizarov7deefb82017-01-31 10:33:17 +0300145
Roman Elizarov66f018c2017-09-29 21:39:03 +0300146If you start by replacing `launch` by `thread`, the compiler produces the following error:
Roman Elizarov7deefb82017-01-31 10:33:17 +0300147
148```
149Error: Kotlin: Suspend functions are only allowed to be called from a coroutine or another suspend function
150```
151
Roman Elizarov419a6c82017-02-09 18:36:22 +0300152That is because [delay] is a special _suspending function_ that does not block a thread, but _suspends_
Roman Elizarov7deefb82017-01-31 10:33:17 +0300153coroutine and it can be only used from a coroutine.
154
Roman Elizarov1293ccd2017-02-01 18:49:54 +0300155### Bridging blocking and non-blocking worlds
Roman Elizarov7deefb82017-01-31 10:33:17 +0300156
Roman Elizarova4d45d22017-11-20 16:47:09 +0300157The first example mixes _non-blocking_ `delay(...)` and _blocking_ `Thread.sleep(...)` in the same code.
158It is easy to get lost which one is blocking and which one is not.
159Let's be explicit about blocking using [runBlocking] coroutine builder:
Roman Elizarov7deefb82017-01-31 10:33:17 +0300160
161```kotlin
Roman Elizarova4d45d22017-11-20 16:47:09 +0300162fun main(args: Array<String>) {
163 launch { // launch new coroutine in background and continue
Roman Elizarov7deefb82017-01-31 10:33:17 +0300164 delay(1000L)
165 println("World!")
166 }
Roman Elizarova4d45d22017-11-20 16:47:09 +0300167 println("Hello,") // main thread continues here immediately
168 runBlocking { // but this expression blocks the main thread
169 delay(2000L) // ... while we delay for 2 seconds to keep JVM alive
170 }
Roman Elizarov7deefb82017-01-31 10:33:17 +0300171}
172```
173
Roman Elizarove8d79342017-08-29 15:21:21 +0300174> 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 +0300175
Roman Elizarov731f0ad2017-02-22 20:48:45 +0300176<!--- TEST
177Hello,
178World!
179-->
180
Roman Elizarov419a6c82017-02-09 18:36:22 +0300181The result is the same, but this code uses only non-blocking [delay].
Tylos81451de2017-12-17 21:33:17 +0100182The main thread, that invokes `runBlocking`, _blocks_ until the coroutine inside `runBlocking` completes.
Roman Elizarov7deefb82017-01-31 10:33:17 +0300183
Roman Elizarova4d45d22017-11-20 16:47:09 +0300184This example can be also rewritten in a more idiomatic way, using `runBlocking` to wrap
185the execution of the main function:
186
187```kotlin
188fun main(args: Array<String>) = runBlocking<Unit> { // start main coroutine
189 launch { // launch new coroutine in background and continue
190 delay(1000L)
191 println("World!")
192 }
193 println("Hello,") // main coroutine continues here immediately
194 delay(2000L) // delaying for 2 seconds to keep JVM alive
195}
196```
197
198> You can get full code [here](core/kotlinx-coroutines-core/src/test/kotlin/guide/example-basic-02b.kt)
199
200<!--- TEST
201Hello,
202World!
203-->
204
205Here `runBlocking<Unit> { ... }` works as an adaptor that is used to start the top-level main coroutine.
206We explicitly specify its `Unit` return type, because a well-formed `main` function in Kotlin has to return `Unit`.
Roman Elizarov7deefb82017-01-31 10:33:17 +0300207
208This is also a way to write unit-tests for suspending functions:
209
210```kotlin
211class MyTest {
212 @Test
213 fun testMySuspendingFunction() = runBlocking<Unit> {
214 // here we can use suspending functions using any assertion style that we like
215 }
216}
217```
Roman Elizarovb3d55a52017-02-03 12:47:21 +0300218
219<!--- CLEAR -->
Roman Elizarov7deefb82017-01-31 10:33:17 +0300220
Roman Elizarov1293ccd2017-02-01 18:49:54 +0300221### Waiting for a job
Roman Elizarov7deefb82017-01-31 10:33:17 +0300222
Roman Elizarov1293ccd2017-02-01 18:49:54 +0300223Delaying for a time while another coroutine is working is not a good approach. Let's explicitly
Roman Elizarov419a6c82017-02-09 18:36:22 +0300224wait (in a non-blocking way) until the background [Job] that we have launched is complete:
Roman Elizarov7deefb82017-01-31 10:33:17 +0300225
226```kotlin
227fun main(args: Array<String>) = runBlocking<Unit> {
Roman Elizarov66f018c2017-09-29 21:39:03 +0300228 val job = launch { // launch new coroutine and keep a reference to its Job
Roman Elizarov7deefb82017-01-31 10:33:17 +0300229 delay(1000L)
230 println("World!")
231 }
232 println("Hello,")
233 job.join() // wait until child coroutine completes
234}
235```
236
Roman Elizarove8d79342017-08-29 15:21:21 +0300237> 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 +0300238
Roman Elizarov731f0ad2017-02-22 20:48:45 +0300239<!--- TEST
240Hello,
241World!
242-->
243
Roman Elizarov7deefb82017-01-31 10:33:17 +0300244Now 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 +0300245the background job in any way. Much better.
Roman Elizarov7deefb82017-01-31 10:33:17 +0300246
Roman Elizarov1293ccd2017-02-01 18:49:54 +0300247### Extract function refactoring
Roman Elizarov7deefb82017-01-31 10:33:17 +0300248
Roman Elizarov66f018c2017-09-29 21:39:03 +0300249Let's extract the block of code inside `launch { ... }` into a separate function. When you
Roman Elizarov7deefb82017-01-31 10:33:17 +0300250perform "Extract function" refactoring on this code you get a new function with `suspend` modifier.
251That is your first _suspending function_. Suspending functions can be used inside coroutines
252just like regular functions, but their additional feature is that they can, in turn,
253use other suspending functions, like `delay` in this example, to _suspend_ execution of a coroutine.
254
255```kotlin
256fun main(args: Array<String>) = runBlocking<Unit> {
Roman Elizarov66f018c2017-09-29 21:39:03 +0300257 val job = launch { doWorld() }
Roman Elizarov7deefb82017-01-31 10:33:17 +0300258 println("Hello,")
259 job.join()
260}
261
262// this is your first suspending function
263suspend fun doWorld() {
264 delay(1000L)
265 println("World!")
266}
267```
268
Roman Elizarove8d79342017-08-29 15:21:21 +0300269> 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 +0300270
Roman Elizarov731f0ad2017-02-22 20:48:45 +0300271<!--- TEST
272Hello,
273World!
274-->
275
Roman Elizarov1293ccd2017-02-01 18:49:54 +0300276### Coroutines ARE light-weight
Roman Elizarov7deefb82017-01-31 10:33:17 +0300277
278Run the following code:
279
280```kotlin
281fun main(args: Array<String>) = runBlocking<Unit> {
Roman Elizarov66f018c2017-09-29 21:39:03 +0300282 val jobs = List(100_000) { // launch a lot of coroutines and list their jobs
283 launch {
Roman Elizarov7deefb82017-01-31 10:33:17 +0300284 delay(1000L)
285 print(".")
286 }
287 }
288 jobs.forEach { it.join() } // wait for all jobs to complete
289}
290```
291
Roman Elizarove8d79342017-08-29 15:21:21 +0300292> 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 +0300293
Roman Elizarov731f0ad2017-02-22 20:48:45 +0300294<!--- TEST lines.size == 1 && lines[0] == ".".repeat(100_000) -->
295
Roman Elizarov66f018c2017-09-29 21:39:03 +0300296It launches 100K coroutines and, after a second, each coroutine prints a dot.
Roman Elizarov7deefb82017-01-31 10:33:17 +0300297Now, try that with threads. What would happen? (Most likely your code will produce some sort of out-of-memory error)
298
Roman Elizarov1293ccd2017-02-01 18:49:54 +0300299### Coroutines are like daemon threads
Roman Elizarov7deefb82017-01-31 10:33:17 +0300300
301The following code launches a long-running coroutine that prints "I'm sleeping" twice a second and then
Roman Elizarov1293ccd2017-02-01 18:49:54 +0300302returns from the main function after some delay:
Roman Elizarov7deefb82017-01-31 10:33:17 +0300303
304```kotlin
305fun main(args: Array<String>) = runBlocking<Unit> {
Roman Elizarov66f018c2017-09-29 21:39:03 +0300306 launch {
Roman Elizarov7deefb82017-01-31 10:33:17 +0300307 repeat(1000) { i ->
308 println("I'm sleeping $i ...")
309 delay(500L)
310 }
311 }
312 delay(1300L) // just quit after delay
313}
314```
315
Roman Elizarove8d79342017-08-29 15:21:21 +0300316> 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 +0300317
318You can run and see that it prints three lines and terminates:
319
Roman Elizarov731f0ad2017-02-22 20:48:45 +0300320```text
Roman Elizarov7deefb82017-01-31 10:33:17 +0300321I'm sleeping 0 ...
322I'm sleeping 1 ...
323I'm sleeping 2 ...
324```
325
Roman Elizarov731f0ad2017-02-22 20:48:45 +0300326<!--- TEST -->
327
Roman Elizarov7deefb82017-01-31 10:33:17 +0300328Active coroutines do not keep the process alive. They are like daemon threads.
329
Roman Elizarov1293ccd2017-02-01 18:49:54 +0300330## Cancellation and timeouts
331
332This section covers coroutine cancellation and timeouts.
333
334### Cancelling coroutine execution
Roman Elizarov7deefb82017-01-31 10:33:17 +0300335
336In small application the return from "main" method might sound like a good idea to get all coroutines
337implicitly terminated. In a larger, long-running application, you need finer-grained control.
Roman Elizarov419a6c82017-02-09 18:36:22 +0300338The [launch] function returns a [Job] that can be used to cancel running coroutine:
Roman Elizarov7deefb82017-01-31 10:33:17 +0300339
340```kotlin
341fun main(args: Array<String>) = runBlocking<Unit> {
Roman Elizarov66f018c2017-09-29 21:39:03 +0300342 val job = launch {
Roman Elizarov7deefb82017-01-31 10:33:17 +0300343 repeat(1000) { i ->
344 println("I'm sleeping $i ...")
345 delay(500L)
346 }
347 }
348 delay(1300L) // delay a bit
Roman Elizarov1293ccd2017-02-01 18:49:54 +0300349 println("main: I'm tired of waiting!")
Roman Elizarov7deefb82017-01-31 10:33:17 +0300350 job.cancel() // cancels the job
Roman Elizarov8b38fa22017-09-27 17:44:31 +0300351 job.join() // waits for job's completion
Roman Elizarov1293ccd2017-02-01 18:49:54 +0300352 println("main: Now I can quit.")
Roman Elizarov7deefb82017-01-31 10:33:17 +0300353}
354```
355
Roman Elizarove8d79342017-08-29 15:21:21 +0300356> 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 +0300357
Roman Elizarov1293ccd2017-02-01 18:49:54 +0300358It produces the following output:
359
Roman Elizarov731f0ad2017-02-22 20:48:45 +0300360```text
Roman Elizarov1293ccd2017-02-01 18:49:54 +0300361I'm sleeping 0 ...
362I'm sleeping 1 ...
363I'm sleeping 2 ...
364main: I'm tired of waiting!
365main: Now I can quit.
366```
367
Roman Elizarov731f0ad2017-02-22 20:48:45 +0300368<!--- TEST -->
369
Roman Elizarov1293ccd2017-02-01 18:49:54 +0300370As 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 +0300371There is also a [Job] extension function [cancelAndJoin]
372that combines [cancel][Job.cancel] and [join][Job.join] invocations.
Roman Elizarov1293ccd2017-02-01 18:49:54 +0300373
374### Cancellation is cooperative
Roman Elizarov7deefb82017-01-31 10:33:17 +0300375
Tair Rzayevaf734622017-02-01 22:30:16 +0200376Coroutine cancellation is _cooperative_. A coroutine code has to cooperate to be cancellable.
Roman Elizarov7deefb82017-01-31 10:33:17 +0300377All the suspending functions in `kotlinx.coroutines` are _cancellable_. They check for cancellation of
Roman Elizarov419a6c82017-02-09 18:36:22 +0300378coroutine and throw [CancellationException] when cancelled. However, if a coroutine is working in
Roman Elizarov7deefb82017-01-31 10:33:17 +0300379a computation and does not check for cancellation, then it cannot be cancelled, like the following
380example shows:
381
382```kotlin
383fun main(args: Array<String>) = runBlocking<Unit> {
Roman Elizarov24cd6542017-08-03 21:20:04 -0700384 val startTime = System.currentTimeMillis()
Roman Elizarov66f018c2017-09-29 21:39:03 +0300385 val job = launch {
Roman Elizarov24cd6542017-08-03 21:20:04 -0700386 var nextPrintTime = startTime
Roman Elizarov7deefb82017-01-31 10:33:17 +0300387 var i = 0
Roman Elizarov8b38fa22017-09-27 17:44:31 +0300388 while (i < 5) { // computation loop, just wastes CPU
Roman Elizarov24cd6542017-08-03 21:20:04 -0700389 // print a message twice a second
390 if (System.currentTimeMillis() >= nextPrintTime) {
Roman Elizarov7deefb82017-01-31 10:33:17 +0300391 println("I'm sleeping ${i++} ...")
Roman Elizarov35d2c342017-07-20 14:54:39 +0300392 nextPrintTime += 500L
Roman Elizarov7deefb82017-01-31 10:33:17 +0300393 }
394 }
395 }
396 delay(1300L) // delay a bit
Roman Elizarov1293ccd2017-02-01 18:49:54 +0300397 println("main: I'm tired of waiting!")
Roman Elizarov8b38fa22017-09-27 17:44:31 +0300398 job.cancelAndJoin() // cancels the job and waits for its completion
Roman Elizarov1293ccd2017-02-01 18:49:54 +0300399 println("main: Now I can quit.")
Roman Elizarov7deefb82017-01-31 10:33:17 +0300400}
401```
402
Roman Elizarove8d79342017-08-29 15:21:21 +0300403> 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 +0300404
Roman Elizarov8b38fa22017-09-27 17:44:31 +0300405Run it to see that it continues to print "I'm sleeping" even after cancellation
406until the job completes by itself after five iterations.
Roman Elizarov7deefb82017-01-31 10:33:17 +0300407
Roman Elizarov731f0ad2017-02-22 20:48:45 +0300408<!--- TEST
409I'm sleeping 0 ...
410I'm sleeping 1 ...
411I'm sleeping 2 ...
412main: I'm tired of waiting!
413I'm sleeping 3 ...
414I'm sleeping 4 ...
Roman Elizarov731f0ad2017-02-22 20:48:45 +0300415main: Now I can quit.
416-->
417
Roman Elizarov1293ccd2017-02-01 18:49:54 +0300418### Making computation code cancellable
Roman Elizarov7deefb82017-01-31 10:33:17 +0300419
420There are two approaches to making computation code cancellable. The first one is to periodically
Roman Elizarov66f018c2017-09-29 21:39:03 +0300421invoke 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 +0300422The other one is to explicitly check the cancellation status. Let us try the later approach.
Roman Elizarov7deefb82017-01-31 10:33:17 +0300423
Roman Elizarov8b38fa22017-09-27 17:44:31 +0300424Replace `while (i < 5)` in the previous example with `while (isActive)` and rerun it.
Roman Elizarov7deefb82017-01-31 10:33:17 +0300425
Roman Elizarovb3d55a52017-02-03 12:47:21 +0300426```kotlin
427fun main(args: Array<String>) = runBlocking<Unit> {
Roman Elizarov24cd6542017-08-03 21:20:04 -0700428 val startTime = System.currentTimeMillis()
Roman Elizarov66f018c2017-09-29 21:39:03 +0300429 val job = launch {
Roman Elizarov24cd6542017-08-03 21:20:04 -0700430 var nextPrintTime = startTime
Roman Elizarovb3d55a52017-02-03 12:47:21 +0300431 var i = 0
432 while (isActive) { // cancellable computation loop
Roman Elizarov24cd6542017-08-03 21:20:04 -0700433 // print a message twice a second
434 if (System.currentTimeMillis() >= nextPrintTime) {
Roman Elizarovb3d55a52017-02-03 12:47:21 +0300435 println("I'm sleeping ${i++} ...")
Roman Elizarov24cd6542017-08-03 21:20:04 -0700436 nextPrintTime += 500L
Roman Elizarovb3d55a52017-02-03 12:47:21 +0300437 }
438 }
439 }
440 delay(1300L) // delay a bit
441 println("main: I'm tired of waiting!")
Roman Elizarov8b38fa22017-09-27 17:44:31 +0300442 job.cancelAndJoin() // cancels the job and waits for its completion
Roman Elizarovb3d55a52017-02-03 12:47:21 +0300443 println("main: Now I can quit.")
444}
445```
446
Roman Elizarove8d79342017-08-29 15:21:21 +0300447> 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 +0300448
Roman Elizarov8b38fa22017-09-27 17:44:31 +0300449As 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 +0300450the code of coroutines via [CoroutineScope] object.
Roman Elizarov7deefb82017-01-31 10:33:17 +0300451
Roman Elizarov731f0ad2017-02-22 20:48:45 +0300452<!--- TEST
453I'm sleeping 0 ...
454I'm sleeping 1 ...
455I'm sleeping 2 ...
456main: I'm tired of waiting!
457main: Now I can quit.
458-->
459
Roman Elizarov1293ccd2017-02-01 18:49:54 +0300460### Closing resources with finally
461
Roman Elizarov419a6c82017-02-09 18:36:22 +0300462Cancellable suspending functions throw [CancellationException] on cancellation which can be handled in
Roman Elizarov66f018c2017-09-29 21:39:03 +0300463all the usual way. For example, `try {...} finally {...}` expression and Kotlin `use` function execute their
Roman Elizarov1293ccd2017-02-01 18:49:54 +0300464finalization actions normally when coroutine is cancelled:
465
466```kotlin
467fun main(args: Array<String>) = runBlocking<Unit> {
Roman Elizarov66f018c2017-09-29 21:39:03 +0300468 val job = launch {
Roman Elizarov1293ccd2017-02-01 18:49:54 +0300469 try {
470 repeat(1000) { i ->
471 println("I'm sleeping $i ...")
472 delay(500L)
473 }
474 } finally {
475 println("I'm running finally")
476 }
477 }
478 delay(1300L) // delay a bit
479 println("main: I'm tired of waiting!")
Roman Elizarov8b38fa22017-09-27 17:44:31 +0300480 job.cancelAndJoin() // cancels the job and waits for its completion
Roman Elizarov1293ccd2017-02-01 18:49:54 +0300481 println("main: Now I can quit.")
482}
483```
484
Roman Elizarove8d79342017-08-29 15:21:21 +0300485> 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 +0300486
Roman Elizarov88396732017-09-27 21:30:47 +0300487Both [join][Job.join] and [cancelAndJoin] wait for all the finalization actions to complete,
488so the example above produces the following output:
Roman Elizarov1293ccd2017-02-01 18:49:54 +0300489
Roman Elizarov731f0ad2017-02-22 20:48:45 +0300490```text
Roman Elizarov1293ccd2017-02-01 18:49:54 +0300491I'm sleeping 0 ...
492I'm sleeping 1 ...
493I'm sleeping 2 ...
494main: I'm tired of waiting!
495I'm running finally
496main: Now I can quit.
497```
498
Roman Elizarov731f0ad2017-02-22 20:48:45 +0300499<!--- TEST -->
500
Roman Elizarov1293ccd2017-02-01 18:49:54 +0300501### Run non-cancellable block
502
503Any attempt to use a suspending function in the `finally` block of the previous example will cause
Roman Elizarov419a6c82017-02-09 18:36:22 +0300504[CancellationException], because the coroutine running this code is cancelled. Usually, this is not a
Roman Elizarov1293ccd2017-02-01 18:49:54 +0300505problem, since all well-behaving closing operations (closing a file, cancelling a job, or closing any kind of a
506communication channel) are usually non-blocking and do not involve any suspending functions. However, in the
507rare case when you need to suspend in the cancelled coroutine you can wrap the corresponding code in
Roman Elizarovf9e13f52017-12-21 12:23:15 +0300508`withContext(NonCancellable) {...}` using [withContext] function and [NonCancellable] context as the following example shows:
Roman Elizarov1293ccd2017-02-01 18:49:54 +0300509
510```kotlin
511fun main(args: Array<String>) = runBlocking<Unit> {
Roman Elizarov66f018c2017-09-29 21:39:03 +0300512 val job = launch {
Roman Elizarov1293ccd2017-02-01 18:49:54 +0300513 try {
514 repeat(1000) { i ->
515 println("I'm sleeping $i ...")
516 delay(500L)
517 }
518 } finally {
Roman Elizarovf9e13f52017-12-21 12:23:15 +0300519 withContext(NonCancellable) {
Roman Elizarov1293ccd2017-02-01 18:49:54 +0300520 println("I'm running finally")
521 delay(1000L)
522 println("And I've just delayed for 1 sec because I'm non-cancellable")
523 }
524 }
525 }
526 delay(1300L) // delay a bit
527 println("main: I'm tired of waiting!")
Roman Elizarov8b38fa22017-09-27 17:44:31 +0300528 job.cancelAndJoin() // cancels the job and waits for its completion
Roman Elizarov1293ccd2017-02-01 18:49:54 +0300529 println("main: Now I can quit.")
530}
531```
532
Roman Elizarove8d79342017-08-29 15:21:21 +0300533> 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 +0300534
Roman Elizarov731f0ad2017-02-22 20:48:45 +0300535<!--- TEST
536I'm sleeping 0 ...
537I'm sleeping 1 ...
538I'm sleeping 2 ...
539main: I'm tired of waiting!
540I'm running finally
541And I've just delayed for 1 sec because I'm non-cancellable
542main: Now I can quit.
543-->
544
Roman Elizarov1293ccd2017-02-01 18:49:54 +0300545### Timeout
546
547The most obvious reason to cancel coroutine execution in practice,
548is because its execution time has exceeded some timeout.
Roman Elizarov419a6c82017-02-09 18:36:22 +0300549While you can manually track the reference to the corresponding [Job] and launch a separate coroutine to cancel
550the tracked one after delay, there is a ready to use [withTimeout] function that does it.
Roman Elizarov1293ccd2017-02-01 18:49:54 +0300551Look at the following example:
552
553```kotlin
554fun main(args: Array<String>) = runBlocking<Unit> {
555 withTimeout(1300L) {
556 repeat(1000) { i ->
557 println("I'm sleeping $i ...")
558 delay(500L)
559 }
560 }
561}
562```
563
Roman Elizarove8d79342017-08-29 15:21:21 +0300564> 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 +0300565
566It produces the following output:
567
Roman Elizarov731f0ad2017-02-22 20:48:45 +0300568```text
Roman Elizarov1293ccd2017-02-01 18:49:54 +0300569I'm sleeping 0 ...
570I'm sleeping 1 ...
571I'm sleeping 2 ...
Roman Elizarov63f6ea22017-09-06 18:42:34 +0300572Exception in thread "main" kotlinx.coroutines.experimental.TimeoutCancellationException: Timed out waiting for 1300 MILLISECONDS
Roman Elizarov1293ccd2017-02-01 18:49:54 +0300573```
574
Roman Elizarov731f0ad2017-02-22 20:48:45 +0300575<!--- TEST STARTS_WITH -->
576
Roman Elizarov63f6ea22017-09-06 18:42:34 +0300577The `TimeoutCancellationException` that is thrown by [withTimeout] is a subclass of [CancellationException].
Roman Elizarovca9d5be2017-04-20 19:23:18 +0300578We have not seen its stack trace printed on the console before. That is because
Roman Elizarov7c864d82017-02-27 10:17:50 +0300579inside a cancelled coroutine `CancellationException` is considered to be a normal reason for coroutine completion.
Roman Elizarov1293ccd2017-02-01 18:49:54 +0300580However, in this example we have used `withTimeout` right inside the `main` function.
581
582Because cancellation is just an exception, all the resources will be closed in a usual way.
Roman Elizarov63f6ea22017-09-06 18:42:34 +0300583You can wrap the code with timeout in `try {...} catch (e: TimeoutCancellationException) {...}` block if
584you need to do some additional action specifically on any kind of timeout or use [withTimeoutOrNull] function
Roman Elizarov8b38fa22017-09-27 17:44:31 +0300585that is similar to [withTimeout], but returns `null` on timeout instead of throwing an exception:
586
587```kotlin
588fun main(args: Array<String>) = runBlocking<Unit> {
589 val result = withTimeoutOrNull(1300L) {
590 repeat(1000) { i ->
591 println("I'm sleeping $i ...")
592 delay(500L)
593 }
594 "Done" // will get cancelled before it produces this result
595 }
596 println("Result is $result")
597}
598```
599
600> You can get full code [here](core/kotlinx-coroutines-core/src/test/kotlin/guide/example-cancel-07.kt)
601
602There is no longer an exception when running this code:
603
604```text
605I'm sleeping 0 ...
606I'm sleeping 1 ...
607I'm sleeping 2 ...
608Result is null
609```
610
611<!--- TEST -->
Roman Elizarov1293ccd2017-02-01 18:49:54 +0300612
613## Composing suspending functions
614
615This section covers various approaches to composition of suspending functions.
616
617### Sequential by default
618
619Assume that we have two suspending functions defined elsewhere that do something useful like some kind of
Roman Elizarovb7721cf2017-02-03 19:23:08 +0300620remote service call or computation. We just pretend they are useful, but actually each one just
621delays for a second for the purpose of this example:
Roman Elizarov1293ccd2017-02-01 18:49:54 +0300622
Roman Elizarovfa7723e2017-02-06 11:17:51 +0300623<!--- INCLUDE .*/example-compose-([0-9]+).kt
Roman Elizarov9fe5f462018-02-21 19:05:52 +0300624import kotlin.system.*
Roman Elizarovfa7723e2017-02-06 11:17:51 +0300625-->
626
Roman Elizarov1293ccd2017-02-01 18:49:54 +0300627```kotlin
628suspend fun doSomethingUsefulOne(): Int {
629 delay(1000L) // pretend we are doing something useful here
630 return 13
631}
632
633suspend fun doSomethingUsefulTwo(): Int {
634 delay(1000L) // pretend we are doing something useful here, too
635 return 29
636}
637```
638
Roman Elizarovfa7723e2017-02-06 11:17:51 +0300639<!--- INCLUDE .*/example-compose-([0-9]+).kt -->
640
Roman Elizarov1293ccd2017-02-01 18:49:54 +0300641What do we do if need to invoke them _sequentially_ -- first `doSomethingUsefulOne` _and then_
642`doSomethingUsefulTwo` and compute the sum of their results?
Ronen Sabagd2d42ea2017-12-24 21:55:06 +0200643In practice we do this if we use the results of the first function to make a decision on whether we need
Roman Elizarov1293ccd2017-02-01 18:49:54 +0300644to invoke the second one or to decide on how to invoke it.
645
646We just use a normal sequential invocation, because the code in the coroutine, just like in the regular
Roman Elizarov32d95322017-02-09 15:57:31 +0300647code, is _sequential_ by default. The following example demonstrates it by measuring the total
Roman Elizarov1293ccd2017-02-01 18:49:54 +0300648time it takes to execute both suspending functions:
649
650```kotlin
651fun main(args: Array<String>) = runBlocking<Unit> {
652 val time = measureTimeMillis {
653 val one = doSomethingUsefulOne()
654 val two = doSomethingUsefulTwo()
655 println("The answer is ${one + two}")
656 }
657 println("Completed in $time ms")
658}
659```
660
Roman Elizarove8d79342017-08-29 15:21:21 +0300661> 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 +0300662
663It produces something like this:
664
Roman Elizarov731f0ad2017-02-22 20:48:45 +0300665```text
Roman Elizarov1293ccd2017-02-01 18:49:54 +0300666The answer is 42
667Completed in 2017 ms
668```
669
Roman Elizarov35d2c342017-07-20 14:54:39 +0300670<!--- TEST ARBITRARY_TIME -->
Roman Elizarov731f0ad2017-02-22 20:48:45 +0300671
Roman Elizarov32d95322017-02-09 15:57:31 +0300672### Concurrent using async
Roman Elizarov1293ccd2017-02-01 18:49:54 +0300673
674What if there are no dependencies between invocation of `doSomethingUsefulOne` and `doSomethingUsefulTwo` and
Roman Elizarov419a6c82017-02-09 18:36:22 +0300675we want to get the answer faster, by doing both _concurrently_? This is where [async] comes to help.
Roman Elizarov1293ccd2017-02-01 18:49:54 +0300676
Roman Elizarov419a6c82017-02-09 18:36:22 +0300677Conceptually, [async] is just like [launch]. It starts a separate coroutine which is a light-weight thread
678that works concurrently with all the other coroutines. The difference is that `launch` returns a [Job] and
679does not carry any resulting value, while `async` returns a [Deferred] -- a light-weight non-blocking future
Roman Elizarov32d95322017-02-09 15:57:31 +0300680that 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 +0300681but `Deferred` is also a `Job`, so you can cancel it if needed.
682
683```kotlin
684fun main(args: Array<String>) = runBlocking<Unit> {
685 val time = measureTimeMillis {
Roman Elizarov66f018c2017-09-29 21:39:03 +0300686 val one = async { doSomethingUsefulOne() }
687 val two = async { doSomethingUsefulTwo() }
Roman Elizarov1293ccd2017-02-01 18:49:54 +0300688 println("The answer is ${one.await() + two.await()}")
689 }
690 println("Completed in $time ms")
691}
692```
693
Roman Elizarove8d79342017-08-29 15:21:21 +0300694> 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 +0300695
696It produces something like this:
697
Roman Elizarov731f0ad2017-02-22 20:48:45 +0300698```text
Roman Elizarov1293ccd2017-02-01 18:49:54 +0300699The answer is 42
700Completed in 1017 ms
701```
702
Roman Elizarov35d2c342017-07-20 14:54:39 +0300703<!--- TEST ARBITRARY_TIME -->
Roman Elizarov731f0ad2017-02-22 20:48:45 +0300704
Roman Elizarov1293ccd2017-02-01 18:49:54 +0300705This is twice as fast, because we have concurrent execution of two coroutines.
706Note, that concurrency with coroutines is always explicit.
707
Roman Elizarov32d95322017-02-09 15:57:31 +0300708### Lazily started async
Roman Elizarov1293ccd2017-02-01 18:49:54 +0300709
Roman Elizarov66f018c2017-09-29 21:39:03 +0300710There is a laziness option to [async] using an optional `start` parameter with a value of [CoroutineStart.LAZY].
Roman Elizarov419a6c82017-02-09 18:36:22 +0300711It starts coroutine only when its result is needed by some
712[await][Deferred.await] or if a [start][Job.start] function
Roman Elizarov32d95322017-02-09 15:57:31 +0300713is invoked. Run the following example that differs from the previous one only by this option:
Roman Elizarov1293ccd2017-02-01 18:49:54 +0300714
715```kotlin
716fun main(args: Array<String>) = runBlocking<Unit> {
717 val time = measureTimeMillis {
Roman Elizarov66f018c2017-09-29 21:39:03 +0300718 val one = async(start = CoroutineStart.LAZY) { doSomethingUsefulOne() }
719 val two = async(start = CoroutineStart.LAZY) { doSomethingUsefulTwo() }
Roman Elizarov1293ccd2017-02-01 18:49:54 +0300720 println("The answer is ${one.await() + two.await()}")
721 }
722 println("Completed in $time ms")
723}
724```
725
Roman Elizarove8d79342017-08-29 15:21:21 +0300726> 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 +0300727
728It produces something like this:
729
Roman Elizarov731f0ad2017-02-22 20:48:45 +0300730```text
Roman Elizarov1293ccd2017-02-01 18:49:54 +0300731The answer is 42
732Completed in 2017 ms
733```
734
Roman Elizarov35d2c342017-07-20 14:54:39 +0300735<!--- TEST ARBITRARY_TIME -->
Roman Elizarov731f0ad2017-02-22 20:48:45 +0300736
Roman Elizarov32d95322017-02-09 15:57:31 +0300737So, we are back to sequential execution, because we _first_ start and await for `one`, _and then_ start and await
738for `two`. It is not the intended use-case for laziness. It is designed as a replacement for
739the standard `lazy` function in cases when computation of the value involves suspending functions.
740
741### Async-style functions
742
743We can define async-style functions that invoke `doSomethingUsefulOne` and `doSomethingUsefulTwo`
Roman Elizarov419a6c82017-02-09 18:36:22 +0300744_asynchronously_ using [async] coroutine builder. It is a good style to name such functions with
Marcin Moskała7e94e702018-01-29 18:39:02 +0100745"Async" suffix to highlight the fact that they only start asynchronous computation and one needs
746to use the resulting deferred value to get the result.
Roman Elizarov32d95322017-02-09 15:57:31 +0300747
748```kotlin
Marcin Moskała7e94e702018-01-29 18:39:02 +0100749// The result type of somethingUsefulOneAsync is Deferred<Int>
750fun somethingUsefulOneAsync() = async {
Roman Elizarov32d95322017-02-09 15:57:31 +0300751 doSomethingUsefulOne()
752}
753
Marcin Moskała7e94e702018-01-29 18:39:02 +0100754// The result type of somethingUsefulTwoAsync is Deferred<Int>
755fun somethingUsefulTwoAsync() = async {
Roman Elizarov32d95322017-02-09 15:57:31 +0300756 doSomethingUsefulTwo()
757}
758```
759
Marcin Moskała7e94e702018-01-29 18:39:02 +0100760Note, that these `xxxAsync` functions are **not** _suspending_ functions. They can be used from anywhere.
Roman Elizarov32d95322017-02-09 15:57:31 +0300761However, their use always implies asynchronous (here meaning _concurrent_) execution of their action
762with the invoking code.
763
764The following example shows their use outside of coroutine:
765
766```kotlin
767// note, that we don't have `runBlocking` to the right of `main` in this example
768fun main(args: Array<String>) {
769 val time = measureTimeMillis {
770 // we can initiate async actions outside of a coroutine
Marcin Moskała7e94e702018-01-29 18:39:02 +0100771 val one = somethingUsefulOneAsync()
772 val two = somethingUsefulTwoAsync()
Roman Elizarov32d95322017-02-09 15:57:31 +0300773 // but waiting for a result must involve either suspending or blocking.
774 // here we use `runBlocking { ... }` to block the main thread while waiting for the result
775 runBlocking {
776 println("The answer is ${one.await() + two.await()}")
777 }
778 }
779 println("Completed in $time ms")
780}
781```
782
Roman Elizarove8d79342017-08-29 15:21:21 +0300783> 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 +0300784
Roman Elizarov35d2c342017-07-20 14:54:39 +0300785<!--- TEST ARBITRARY_TIME
Roman Elizarov731f0ad2017-02-22 20:48:45 +0300786The answer is 42
787Completed in 1085 ms
788-->
789
Roman Elizarov2f6d7c92017-02-03 15:16:07 +0300790## Coroutine context and dispatchers
791
Roman Elizarov66f018c2017-09-29 21:39:03 +0300792Coroutines always execute in some context which is represented by the value of
793[CoroutineContext](https://kotlinlang.org/api/latest/jvm/stdlib/kotlin.coroutines.experimental/-coroutine-context/)
794type, defined in the Kotlin standard library.
795
796The coroutine context is a set of various elements. The main elements are the [Job] of the coroutine,
797which we've seen before, and its dispatcher, which is covered in this section.
Roman Elizarov2f6d7c92017-02-03 15:16:07 +0300798
799### Dispatchers and threads
800
Roman Elizarov66f018c2017-09-29 21:39:03 +0300801Coroutine context includes a _coroutine dispatcher_ (see [CoroutineDispatcher]) that determines what thread or threads
Roman Elizarov2f6d7c92017-02-03 15:16:07 +0300802the corresponding coroutine uses for its execution. Coroutine dispatcher can confine coroutine execution
Roman Elizarov66f018c2017-09-29 21:39:03 +0300803to a specific thread, dispatch it to a thread pool, or let it run unconfined.
804
805All coroutines builders like [launch] and [async] accept an optional
806[CoroutineContext](https://kotlinlang.org/api/latest/jvm/stdlib/kotlin.coroutines.experimental/-coroutine-context/)
807parameter that can be used to explicitly specify the dispatcher for new coroutine and other context elements.
808
809Try the following example:
Roman Elizarov2f6d7c92017-02-03 15:16:07 +0300810
Roman Elizarov9fe5f462018-02-21 19:05:52 +0300811<!--- INCLUDE
812import kotlin.coroutines.experimental.*
813-->
814
Roman Elizarov2f6d7c92017-02-03 15:16:07 +0300815```kotlin
816fun main(args: Array<String>) = runBlocking<Unit> {
817 val jobs = arrayListOf<Job>()
818 jobs += launch(Unconfined) { // not confined -- will work with main thread
Roman Elizarov43e3af72017-07-21 16:01:31 +0300819 println(" 'Unconfined': I'm working in thread ${Thread.currentThread().name}")
Roman Elizarov2f6d7c92017-02-03 15:16:07 +0300820 }
Roman Elizarov43e3af72017-07-21 16:01:31 +0300821 jobs += launch(coroutineContext) { // context of the parent, runBlocking coroutine
822 println("'coroutineContext': I'm working in thread ${Thread.currentThread().name}")
Roman Elizarov2f6d7c92017-02-03 15:16:07 +0300823 }
824 jobs += launch(CommonPool) { // will get dispatched to ForkJoinPool.commonPool (or equivalent)
Roman Elizarov43e3af72017-07-21 16:01:31 +0300825 println(" 'CommonPool': I'm working in thread ${Thread.currentThread().name}")
Roman Elizarov2f6d7c92017-02-03 15:16:07 +0300826 }
827 jobs += launch(newSingleThreadContext("MyOwnThread")) { // will get its own new thread
Roman Elizarov43e3af72017-07-21 16:01:31 +0300828 println(" 'newSTC': I'm working in thread ${Thread.currentThread().name}")
Roman Elizarov2f6d7c92017-02-03 15:16:07 +0300829 }
830 jobs.forEach { it.join() }
831}
832```
833
Roman Elizarove8d79342017-08-29 15:21:21 +0300834> 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 +0300835
836It produces the following output (maybe in different order):
837
Roman Elizarov731f0ad2017-02-22 20:48:45 +0300838```text
Roman Elizarov43e3af72017-07-21 16:01:31 +0300839 'Unconfined': I'm working in thread main
840 'CommonPool': I'm working in thread ForkJoinPool.commonPool-worker-1
841 'newSTC': I'm working in thread MyOwnThread
842'coroutineContext': I'm working in thread main
Roman Elizarov2f6d7c92017-02-03 15:16:07 +0300843```
844
Roman Elizarov731f0ad2017-02-22 20:48:45 +0300845<!--- TEST LINES_START_UNORDERED -->
846
Roman Elizarovd9ae2bc2017-10-20 17:36:56 +0800847The default dispatcher that we've used in previous sections is representend by [DefaultDispatcher], which
Roman Elizarov66f018c2017-09-29 21:39:03 +0300848is equal to [CommonPool] in the current implementation. So, `launch { ... }` is the same
Charles Muchenefa13beb2018-01-08 16:56:54 +0300849as `launch(DefaultDispatcher) { ... }`, which is the same as `launch(CommonPool) { ... }`.
Roman Elizarov66f018c2017-09-29 21:39:03 +0300850
Roman Elizarov9fe5f462018-02-21 19:05:52 +0300851The difference between parent
852[coroutineContext](https://kotlinlang.org/api/latest/jvm/stdlib/kotlin.coroutines.experimental/coroutine-context.html) and
Roman Elizarov43e3af72017-07-21 16:01:31 +0300853[Unconfined] context will be shown later.
Roman Elizarov2f6d7c92017-02-03 15:16:07 +0300854
Roman Elizarovd9ae2bc2017-10-20 17:36:56 +0800855Note, that [newSingleThreadContext] creates a new thread, which is a very expensive resource.
856In a real application it must be either released, when no longer needed, using [close][ThreadPoolDispatcher.close]
857function, or stored in a top-level variable and reused throughout the application.
858
Roman Elizarov2f6d7c92017-02-03 15:16:07 +0300859### Unconfined vs confined dispatcher
860
Roman Elizarov419a6c82017-02-09 18:36:22 +0300861The [Unconfined] coroutine dispatcher starts coroutine in the caller thread, but only until the
Roman Elizarov2f6d7c92017-02-03 15:16:07 +0300862first suspension point. After suspension it resumes in the thread that is fully determined by the
863suspending function that was invoked. Unconfined dispatcher is appropriate when coroutine does not
864consume CPU time nor updates any shared data (like UI) that is confined to a specific thread.
865
Roman Elizarov9fe5f462018-02-21 19:05:52 +0300866On the other side,
867[coroutineContext](https://kotlinlang.org/api/latest/jvm/stdlib/kotlin.coroutines.experimental/coroutine-context.html)
868property, that is available inside any coroutine, is a reference to a context of this particular coroutine.
Roman Elizarov66f018c2017-09-29 21:39:03 +0300869This way, a parent context can be inherited. The default dispatcher for [runBlocking] coroutine, in particular,
870is confined to the invoker thread, so inheriting it has the effect of confining execution to
Roman Elizarov2f6d7c92017-02-03 15:16:07 +0300871this thread with a predictable FIFO scheduling.
872
Roman Elizarov9fe5f462018-02-21 19:05:52 +0300873<!--- INCLUDE
874import kotlin.coroutines.experimental.*
875-->
876
Roman Elizarov2f6d7c92017-02-03 15:16:07 +0300877```kotlin
878fun main(args: Array<String>) = runBlocking<Unit> {
879 val jobs = arrayListOf<Job>()
880 jobs += launch(Unconfined) { // not confined -- will work with main thread
Roman Elizarov43e3af72017-07-21 16:01:31 +0300881 println(" 'Unconfined': I'm working in thread ${Thread.currentThread().name}")
Roman Elizarovd0021622017-03-10 15:43:38 +0300882 delay(500)
Roman Elizarov43e3af72017-07-21 16:01:31 +0300883 println(" 'Unconfined': After delay in thread ${Thread.currentThread().name}")
Roman Elizarov2f6d7c92017-02-03 15:16:07 +0300884 }
Roman Elizarov43e3af72017-07-21 16:01:31 +0300885 jobs += launch(coroutineContext) { // context of the parent, runBlocking coroutine
886 println("'coroutineContext': I'm working in thread ${Thread.currentThread().name}")
Roman Elizarov2f6d7c92017-02-03 15:16:07 +0300887 delay(1000)
Roman Elizarov43e3af72017-07-21 16:01:31 +0300888 println("'coroutineContext': After delay in thread ${Thread.currentThread().name}")
Roman Elizarov2f6d7c92017-02-03 15:16:07 +0300889 }
890 jobs.forEach { it.join() }
891}
892```
893
Roman Elizarove8d79342017-08-29 15:21:21 +0300894> 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 +0300895
896Produces the output:
897
Roman Elizarov731f0ad2017-02-22 20:48:45 +0300898```text
Roman Elizarov43e3af72017-07-21 16:01:31 +0300899 'Unconfined': I'm working in thread main
900'coroutineContext': I'm working in thread main
901 'Unconfined': After delay in thread kotlinx.coroutines.DefaultExecutor
902'coroutineContext': After delay in thread main
Roman Elizarov2f6d7c92017-02-03 15:16:07 +0300903```
Roman Elizarov731f0ad2017-02-22 20:48:45 +0300904
905<!--- TEST LINES_START -->
Roman Elizarov2f6d7c92017-02-03 15:16:07 +0300906
Roman Elizarov43e3af72017-07-21 16:01:31 +0300907So, the coroutine that had inherited `coroutineContext` of `runBlocking {...}` continues to execute
908in the `main` thread, while the unconfined one had resumed in the default executor thread that [delay]
909function is using.
Roman Elizarov2f6d7c92017-02-03 15:16:07 +0300910
911### Debugging coroutines and threads
912
Roman Elizarov419a6c82017-02-09 18:36:22 +0300913Coroutines can suspend on one thread and resume on another thread with [Unconfined] dispatcher or
Roman Elizarov66f018c2017-09-29 21:39:03 +0300914with a default multi-threaded dispatcher. Even with a single-threaded dispatcher it might be hard to
Roman Elizarov2f6d7c92017-02-03 15:16:07 +0300915figure out what coroutine was doing what, where, and when. The common approach to debugging applications with
916threads is to print the thread name in the log file on each log statement. This feature is universally supported
917by logging frameworks. When using coroutines, the thread name alone does not give much of a context, so
918`kotlinx.coroutines` includes debugging facilities to make it easier.
919
920Run the following code with `-Dkotlinx.coroutines.debug` JVM option:
921
Roman Elizarov9fe5f462018-02-21 19:05:52 +0300922<!--- INCLUDE
923import kotlin.coroutines.experimental.*
924-->
925
Roman Elizarov2f6d7c92017-02-03 15:16:07 +0300926```kotlin
927fun log(msg: String) = println("[${Thread.currentThread().name}] $msg")
928
929fun main(args: Array<String>) = runBlocking<Unit> {
Roman Elizarov43e3af72017-07-21 16:01:31 +0300930 val a = async(coroutineContext) {
Roman Elizarov2f6d7c92017-02-03 15:16:07 +0300931 log("I'm computing a piece of the answer")
932 6
933 }
Roman Elizarov43e3af72017-07-21 16:01:31 +0300934 val b = async(coroutineContext) {
Roman Elizarov2f6d7c92017-02-03 15:16:07 +0300935 log("I'm computing another piece of the answer")
936 7
937 }
938 log("The answer is ${a.await() * b.await()}")
939}
940```
941
Roman Elizarove8d79342017-08-29 15:21:21 +0300942> 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 +0300943
Roman Elizarovb7721cf2017-02-03 19:23:08 +0300944There are three coroutines. The main coroutine (#1) -- `runBlocking` one,
Roman Elizarov2f6d7c92017-02-03 15:16:07 +0300945and two coroutines computing deferred values `a` (#2) and `b` (#3).
946They are all executing in the context of `runBlocking` and are confined to the main thread.
947The output of this code is:
948
Roman Elizarov731f0ad2017-02-22 20:48:45 +0300949```text
Roman Elizarov2f6d7c92017-02-03 15:16:07 +0300950[main @coroutine#2] I'm computing a piece of the answer
951[main @coroutine#3] I'm computing another piece of the answer
952[main @coroutine#1] The answer is 42
953```
954
Kirill Timofeeva5186962017-10-25 14:25:47 +0300955<!--- TEST FLEXIBLE_THREAD -->
Roman Elizarov731f0ad2017-02-22 20:48:45 +0300956
Roman Elizarov2f6d7c92017-02-03 15:16:07 +0300957The `log` function prints the name of the thread in square brackets and you can see, that it is the `main`
958thread, but the identifier of the currently executing coroutine is appended to it. This identifier
959is consecutively assigned to all created coroutines when debugging mode is turned on.
960
Roman Elizarov419a6c82017-02-09 18:36:22 +0300961You can read more about debugging facilities in the documentation for [newCoroutineContext] function.
Roman Elizarov2f6d7c92017-02-03 15:16:07 +0300962
963### Jumping between threads
964
965Run the following code with `-Dkotlinx.coroutines.debug` JVM option:
966
967```kotlin
968fun log(msg: String) = println("[${Thread.currentThread().name}] $msg")
969
970fun main(args: Array<String>) {
Roman Elizarovd9ae2bc2017-10-20 17:36:56 +0800971 newSingleThreadContext("Ctx1").use { ctx1 ->
972 newSingleThreadContext("Ctx2").use { ctx2 ->
973 runBlocking(ctx1) {
974 log("Started in ctx1")
Roman Elizarovf9e13f52017-12-21 12:23:15 +0300975 withContext(ctx2) {
Roman Elizarovd9ae2bc2017-10-20 17:36:56 +0800976 log("Working in ctx2")
977 }
978 log("Back to ctx1")
979 }
Roman Elizarov2f6d7c92017-02-03 15:16:07 +0300980 }
Roman Elizarov2f6d7c92017-02-03 15:16:07 +0300981 }
982}
983```
984
Roman Elizarove8d79342017-08-29 15:21:21 +0300985> 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 +0300986
Roman Elizarovd9ae2bc2017-10-20 17:36:56 +0800987It demonstrates several new techniques. One is using [runBlocking] with an explicitly specified context, and
Roman Elizarovf9e13f52017-12-21 12:23:15 +0300988the other one is using [withContext] function to change a context of a coroutine while still staying in the
Roman Elizarov2f6d7c92017-02-03 15:16:07 +0300989same coroutine as you can see in the output below:
990
Roman Elizarov731f0ad2017-02-22 20:48:45 +0300991```text
Roman Elizarov2f6d7c92017-02-03 15:16:07 +0300992[Ctx1 @coroutine#1] Started in ctx1
993[Ctx2 @coroutine#1] Working in ctx2
994[Ctx1 @coroutine#1] Back to ctx1
995```
996
Roman Elizarov731f0ad2017-02-22 20:48:45 +0300997<!--- TEST -->
998
Roman Elizarovd9ae2bc2017-10-20 17:36:56 +0800999
Artsiom Chapialioue185ed62018-06-03 19:34:22 -04001000Note, that this example also uses `use` function from the Kotlin standard library to release threads that
Roman Elizarovd9ae2bc2017-10-20 17:36:56 +08001001are created with [newSingleThreadContext] when they are no longer needed.
1002
Roman Elizarov2f6d7c92017-02-03 15:16:07 +03001003### Job in the context
1004
Roman Elizarov66f018c2017-09-29 21:39:03 +03001005The coroutine's [Job] is part of its context. The coroutine can retrieve it from its own context
Roman Elizarov43e3af72017-07-21 16:01:31 +03001006using `coroutineContext[Job]` expression:
Roman Elizarov2f6d7c92017-02-03 15:16:07 +03001007
Roman Elizarov9fe5f462018-02-21 19:05:52 +03001008<!--- INCLUDE
1009import kotlin.coroutines.experimental.*
1010-->
1011
Roman Elizarov2f6d7c92017-02-03 15:16:07 +03001012```kotlin
1013fun main(args: Array<String>) = runBlocking<Unit> {
Roman Elizarov43e3af72017-07-21 16:01:31 +03001014 println("My job is ${coroutineContext[Job]}")
Roman Elizarov2f6d7c92017-02-03 15:16:07 +03001015}
1016```
1017
Roman Elizarove8d79342017-08-29 15:21:21 +03001018> 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 +03001019
Roman Elizarov66f018c2017-09-29 21:39:03 +03001020It produces something like that when running in [debug mode](#debugging-coroutines-and-threads):
Roman Elizarov2f6d7c92017-02-03 15:16:07 +03001021
1022```
Roman Elizarov8b38fa22017-09-27 17:44:31 +03001023My job is "coroutine#1":BlockingCoroutine{Active}@6d311334
Roman Elizarov2f6d7c92017-02-03 15:16:07 +03001024```
1025
Roman Elizarov8b38fa22017-09-27 17:44:31 +03001026<!--- TEST lines.size == 1 && lines[0].startsWith("My job is \"coroutine#1\":BlockingCoroutine{Active}@") -->
Roman Elizarov731f0ad2017-02-22 20:48:45 +03001027
Roman Elizarov43e3af72017-07-21 16:01:31 +03001028So, [isActive][CoroutineScope.isActive] in [CoroutineScope] is just a convenient shortcut for
Roman Elizarov9fe5f462018-02-21 19:05:52 +03001029`coroutineContext[Job]?.isActive == true`.
Roman Elizarov2f6d7c92017-02-03 15:16:07 +03001030
1031### Children of a coroutine
1032
Roman Elizarov9fe5f462018-02-21 19:05:52 +03001033When
1034[coroutineContext](https://kotlinlang.org/api/latest/jvm/stdlib/kotlin.coroutines.experimental/coroutine-context.html)
1035of a coroutine is used to launch another coroutine,
Roman Elizarov419a6c82017-02-09 18:36:22 +03001036the [Job] of the new coroutine becomes
Roman Elizarov2f6d7c92017-02-03 15:16:07 +03001037a _child_ of the parent coroutine's job. When the parent coroutine is cancelled, all its children
1038are recursively cancelled, too.
1039
Roman Elizarov9fe5f462018-02-21 19:05:52 +03001040<!--- INCLUDE
1041import kotlin.coroutines.experimental.*
1042-->
1043
Roman Elizarov2f6d7c92017-02-03 15:16:07 +03001044```kotlin
1045fun main(args: Array<String>) = runBlocking<Unit> {
Roman Elizarov66f018c2017-09-29 21:39:03 +03001046 // launch a coroutine to process some kind of incoming request
1047 val request = launch {
Roman Elizarov2f6d7c92017-02-03 15:16:07 +03001048 // it spawns two other jobs, one with its separate context
Roman Elizarov66f018c2017-09-29 21:39:03 +03001049 val job1 = launch {
Roman Elizarov2f6d7c92017-02-03 15:16:07 +03001050 println("job1: I have my own context and execute independently!")
1051 delay(1000)
1052 println("job1: I am not affected by cancellation of the request")
1053 }
1054 // and the other inherits the parent context
Roman Elizarov43e3af72017-07-21 16:01:31 +03001055 val job2 = launch(coroutineContext) {
Roman Elizarov74619c12017-11-09 10:32:15 +03001056 delay(100)
Roman Elizarov2f6d7c92017-02-03 15:16:07 +03001057 println("job2: I am a child of the request coroutine")
1058 delay(1000)
1059 println("job2: I will not execute this line if my parent request is cancelled")
1060 }
1061 // request completes when both its sub-jobs complete:
1062 job1.join()
1063 job2.join()
1064 }
1065 delay(500)
1066 request.cancel() // cancel processing of the request
1067 delay(1000) // delay a second to see what happens
1068 println("main: Who has survived request cancellation?")
1069}
1070```
1071
Roman Elizarove8d79342017-08-29 15:21:21 +03001072> 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 +03001073
1074The output of this code is:
1075
Roman Elizarov731f0ad2017-02-22 20:48:45 +03001076```text
Roman Elizarov2f6d7c92017-02-03 15:16:07 +03001077job1: I have my own context and execute independently!
1078job2: I am a child of the request coroutine
1079job1: I am not affected by cancellation of the request
1080main: Who has survived request cancellation?
1081```
1082
Roman Elizarov731f0ad2017-02-22 20:48:45 +03001083<!--- TEST -->
1084
Roman Elizarov2f6d7c92017-02-03 15:16:07 +03001085### Combining contexts
1086
Roman Elizarov66f018c2017-09-29 21:39:03 +03001087Coroutine contexts can be combined using `+` operator. The context on the right-hand side replaces relevant entries
Roman Elizarov419a6c82017-02-09 18:36:22 +03001088of 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 +03001089its dispatcher replaced:
1090
Roman Elizarov9fe5f462018-02-21 19:05:52 +03001091<!--- INCLUDE
1092import kotlin.coroutines.experimental.*
1093-->
1094
Roman Elizarov2f6d7c92017-02-03 15:16:07 +03001095```kotlin
1096fun main(args: Array<String>) = runBlocking<Unit> {
1097 // start a coroutine to process some kind of incoming request
Roman Elizarov43e3af72017-07-21 16:01:31 +03001098 val request = launch(coroutineContext) { // use the context of `runBlocking`
Roman Elizarov2f6d7c92017-02-03 15:16:07 +03001099 // spawns CPU-intensive child job in CommonPool !!!
Roman Elizarov43e3af72017-07-21 16:01:31 +03001100 val job = launch(coroutineContext + CommonPool) {
Roman Elizarov2f6d7c92017-02-03 15:16:07 +03001101 println("job: I am a child of the request coroutine, but with a different dispatcher")
1102 delay(1000)
1103 println("job: I will not execute this line if my parent request is cancelled")
1104 }
1105 job.join() // request completes when its sub-job completes
1106 }
1107 delay(500)
1108 request.cancel() // cancel processing of the request
1109 delay(1000) // delay a second to see what happens
1110 println("main: Who has survived request cancellation?")
1111}
1112```
1113
Roman Elizarove8d79342017-08-29 15:21:21 +03001114> 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 +03001115
1116The expected outcome of this code is:
1117
Roman Elizarov731f0ad2017-02-22 20:48:45 +03001118```text
Roman Elizarov2f6d7c92017-02-03 15:16:07 +03001119job: I am a child of the request coroutine, but with a different dispatcher
1120main: Who has survived request cancellation?
1121```
1122
Roman Elizarov731f0ad2017-02-22 20:48:45 +03001123<!--- TEST -->
1124
Roman Elizarov8b38fa22017-09-27 17:44:31 +03001125### Parental responsibilities
1126
1127A parent coroutine always waits for completion of all its children. Parent does not have to explicitly track
Roman Elizarov88396732017-09-27 21:30:47 +03001128all 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 +03001129
Roman Elizarov9fe5f462018-02-21 19:05:52 +03001130<!--- INCLUDE
1131import kotlin.coroutines.experimental.*
1132-->
1133
Roman Elizarov8b38fa22017-09-27 17:44:31 +03001134```kotlin
1135fun main(args: Array<String>) = runBlocking<Unit> {
Roman Elizarov66f018c2017-09-29 21:39:03 +03001136 // launch a coroutine to process some kind of incoming request
1137 val request = launch {
Roman Elizarov8b38fa22017-09-27 17:44:31 +03001138 repeat(3) { i -> // launch a few children jobs
1139 launch(coroutineContext) {
1140 delay((i + 1) * 200L) // variable delay 200ms, 400ms, 600ms
1141 println("Coroutine $i is done")
1142 }
1143 }
1144 println("request: I'm done and I don't explicitly join my children that are still active")
1145 }
1146 request.join() // wait for completion of the request, including all its children
1147 println("Now processing of the request is complete")
1148}
1149```
1150
1151> You can get full code [here](core/kotlinx-coroutines-core/src/test/kotlin/guide/example-context-08.kt)
1152
1153The result is going to be:
1154
1155```text
1156request: I'm done and I don't explicitly join my children that are still active
1157Coroutine 0 is done
1158Coroutine 1 is done
1159Coroutine 2 is done
1160Now processing of the request is complete
1161```
1162
1163<!--- TEST -->
1164
Roman Elizarov2f6d7c92017-02-03 15:16:07 +03001165### Naming coroutines for debugging
1166
Roman Elizarovb7721cf2017-02-03 19:23:08 +03001167Automatically assigned ids are good when coroutines log often and you just need to correlate log records
Roman Elizarov2f6d7c92017-02-03 15:16:07 +03001168coming from the same coroutine. However, when coroutine is tied to the processing of a specific request
1169or doing some specific background task, it is better to name it explicitly for debugging purposes.
Roman Elizarov66f018c2017-09-29 21:39:03 +03001170[CoroutineName] context element serves the same function as a thread name. It'll get displayed in the thread name that
1171is executing this coroutine when [debugging mode](#debugging-coroutines-and-threads) is turned on.
Roman Elizarov2f6d7c92017-02-03 15:16:07 +03001172
1173The following example demonstrates this concept:
1174
1175```kotlin
1176fun log(msg: String) = println("[${Thread.currentThread().name}] $msg")
1177
1178fun main(args: Array<String>) = runBlocking(CoroutineName("main")) {
1179 log("Started main coroutine")
1180 // run two background value computations
Roman Elizarov66f018c2017-09-29 21:39:03 +03001181 val v1 = async(CoroutineName("v1coroutine")) {
Roman Elizarov2f6d7c92017-02-03 15:16:07 +03001182 delay(500)
Roman Elizarov674efea2017-10-21 17:16:30 +03001183 log("Computing v1")
Roman Elizarov2f6d7c92017-02-03 15:16:07 +03001184 252
1185 }
Roman Elizarov66f018c2017-09-29 21:39:03 +03001186 val v2 = async(CoroutineName("v2coroutine")) {
Roman Elizarov2f6d7c92017-02-03 15:16:07 +03001187 delay(1000)
Roman Elizarov674efea2017-10-21 17:16:30 +03001188 log("Computing v2")
Roman Elizarov2f6d7c92017-02-03 15:16:07 +03001189 6
1190 }
1191 log("The answer for v1 / v2 = ${v1.await() / v2.await()}")
1192}
1193```
1194
Roman Elizarov8b38fa22017-09-27 17:44:31 +03001195> 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 +03001196
1197The output it produces with `-Dkotlinx.coroutines.debug` JVM option is similar to:
1198
Roman Elizarov731f0ad2017-02-22 20:48:45 +03001199```text
Roman Elizarov2f6d7c92017-02-03 15:16:07 +03001200[main @main#1] Started main coroutine
1201[ForkJoinPool.commonPool-worker-1 @v1coroutine#2] Computing v1
1202[ForkJoinPool.commonPool-worker-2 @v2coroutine#3] Computing v2
1203[main @main#1] The answer for v1 / v2 = 42
1204```
Roman Elizarov1293ccd2017-02-01 18:49:54 +03001205
Roman Elizarov731f0ad2017-02-22 20:48:45 +03001206<!--- TEST FLEXIBLE_THREAD -->
1207
Roman Elizarov2fd7cb32017-02-11 23:18:59 +03001208### Cancellation via explicit job
1209
1210Let us put our knowledge about contexts, children and jobs together. Assume that our application has
1211an object with a lifecycle, but that object is not a coroutine. For example, we are writing an Android application
1212and launch various coroutines in the context of an Android activity to perform asynchronous operations to fetch
1213and update data, do animations, etc. All of these coroutines must be cancelled when activity is destroyed
1214to avoid memory leaks.
1215
1216We can manage a lifecycle of our coroutines by creating an instance of [Job] that is tied to
Roman Elizarov88396732017-09-27 21:30:47 +03001217the lifecycle of our activity. A job instance is created using [Job()] factory function
Roman Elizarove8f694e2017-11-28 10:12:00 +03001218as the following example shows. For convenience, rather than using `launch(coroutineContext + job)` expression,
1219we can write `launch(coroutineContext, parent = job)` to make explicit the fact that the parent job is being used.
1220
1221Now, a single invocation of [Job.cancel] cancels all the children we've launched.
Roman Elizarov8b38fa22017-09-27 17:44:31 +03001222Moreover, [Job.join] waits for all of them to complete, so we can also use [cancelAndJoin] here in
1223this example:
Roman Elizarov2fd7cb32017-02-11 23:18:59 +03001224
Roman Elizarov9fe5f462018-02-21 19:05:52 +03001225<!--- INCLUDE
1226import kotlin.coroutines.experimental.*
1227-->
1228
Roman Elizarov2fd7cb32017-02-11 23:18:59 +03001229```kotlin
1230fun main(args: Array<String>) = runBlocking<Unit> {
1231 val job = Job() // create a job object to manage our lifecycle
1232 // now launch ten coroutines for a demo, each working for a different time
1233 val coroutines = List(10) { i ->
1234 // they are all children of our job object
Roman Elizarove8f694e2017-11-28 10:12:00 +03001235 launch(coroutineContext, parent = job) { // we use the context of main runBlocking thread, but with our parent job
Roman Elizarov8b38fa22017-09-27 17:44:31 +03001236 delay((i + 1) * 200L) // variable delay 200ms, 400ms, ... etc
Roman Elizarov2fd7cb32017-02-11 23:18:59 +03001237 println("Coroutine $i is done")
1238 }
1239 }
1240 println("Launched ${coroutines.size} coroutines")
1241 delay(500L) // delay for half a second
Roman Elizarov8b38fa22017-09-27 17:44:31 +03001242 println("Cancelling the job!")
1243 job.cancelAndJoin() // cancel all our coroutines and wait for all of them to complete
Roman Elizarov2fd7cb32017-02-11 23:18:59 +03001244}
1245```
1246
Roman Elizarov8b38fa22017-09-27 17:44:31 +03001247> 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 +03001248
1249The output of this example is:
1250
Roman Elizarov731f0ad2017-02-22 20:48:45 +03001251```text
Roman Elizarov2fd7cb32017-02-11 23:18:59 +03001252Launched 10 coroutines
1253Coroutine 0 is done
1254Coroutine 1 is done
Roman Elizarov8b38fa22017-09-27 17:44:31 +03001255Cancelling the job!
Roman Elizarov2fd7cb32017-02-11 23:18:59 +03001256```
1257
Roman Elizarov731f0ad2017-02-22 20:48:45 +03001258<!--- TEST -->
1259
Roman Elizarov2fd7cb32017-02-11 23:18:59 +03001260As you can see, only the first three coroutines had printed a message and the others were cancelled
Roman Elizarov8b38fa22017-09-27 17:44:31 +03001261by a single invocation of `job.cancelAndJoin()`. So all we need to do in our hypothetical Android
Roman Elizarov2fd7cb32017-02-11 23:18:59 +03001262application is to create a parent job object when activity is created, use it for child coroutines,
Roman Elizarov8b38fa22017-09-27 17:44:31 +03001263and cancel it when activity is destroyed. We cannot `join` them in the case of Android lifecycle,
1264since it is synchronous, but this joining ability is useful when building backend services to ensure bounded
1265resource usage.
Roman Elizarov2fd7cb32017-02-11 23:18:59 +03001266
Roman Elizarovb7721cf2017-02-03 19:23:08 +03001267## Channels
Roman Elizarov7deefb82017-01-31 10:33:17 +03001268
Roman Elizarovb7721cf2017-02-03 19:23:08 +03001269Deferred values provide a convenient way to transfer a single value between coroutines.
1270Channels provide a way to transfer a stream of values.
1271
1272<!--- INCLUDE .*/example-channel-([0-9]+).kt
1273import kotlinx.coroutines.experimental.channels.*
1274-->
1275
1276### Channel basics
1277
Roman Elizarov419a6c82017-02-09 18:36:22 +03001278A [Channel] is conceptually very similar to `BlockingQueue`. One key difference is that
1279instead of a blocking `put` operation it has a suspending [send][SendChannel.send], and instead of
1280a blocking `take` operation it has a suspending [receive][ReceiveChannel.receive].
Roman Elizarovb7721cf2017-02-03 19:23:08 +03001281
1282```kotlin
1283fun main(args: Array<String>) = runBlocking<Unit> {
1284 val channel = Channel<Int>()
Roman Elizarov66f018c2017-09-29 21:39:03 +03001285 launch {
Roman Elizarovb7721cf2017-02-03 19:23:08 +03001286 // this might be heavy CPU-consuming computation or async logic, we'll just send five squares
1287 for (x in 1..5) channel.send(x * x)
1288 }
1289 // here we print five received integers:
1290 repeat(5) { println(channel.receive()) }
1291 println("Done!")
1292}
1293```
1294
Roman Elizarove8d79342017-08-29 15:21:21 +03001295> 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 +03001296
Roman Elizarov731f0ad2017-02-22 20:48:45 +03001297The output of this code is:
1298
1299```text
13001
13014
13029
130316
130425
1305Done!
1306```
1307
1308<!--- TEST -->
1309
Roman Elizarovb7721cf2017-02-03 19:23:08 +03001310### Closing and iteration over channels
1311
1312Unlike a queue, a channel can be closed to indicate that no more elements are coming.
1313On the receiver side it is convenient to use a regular `for` loop to receive elements
1314from the channel.
1315
Roman Elizarov419a6c82017-02-09 18:36:22 +03001316Conceptually, a [close][SendChannel.close] is like sending a special close token to the channel.
Roman Elizarovb7721cf2017-02-03 19:23:08 +03001317The iteration stops as soon as this close token is received, so there is a guarantee
1318that all previously sent elements before the close are received:
1319
1320```kotlin
1321fun main(args: Array<String>) = runBlocking<Unit> {
1322 val channel = Channel<Int>()
Roman Elizarov66f018c2017-09-29 21:39:03 +03001323 launch {
Roman Elizarovb7721cf2017-02-03 19:23:08 +03001324 for (x in 1..5) channel.send(x * x)
1325 channel.close() // we're done sending
1326 }
1327 // here we print received values using `for` loop (until the channel is closed)
1328 for (y in channel) println(y)
1329 println("Done!")
1330}
1331```
1332
Roman Elizarove8d79342017-08-29 15:21:21 +03001333> 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 +03001334
Roman Elizarov731f0ad2017-02-22 20:48:45 +03001335<!--- TEST
13361
13374
13389
133916
134025
1341Done!
1342-->
1343
Roman Elizarovb7721cf2017-02-03 19:23:08 +03001344### Building channel producers
1345
Roman Elizarova5e653f2017-02-13 13:49:55 +03001346The pattern where a coroutine is producing a sequence of elements is quite common.
1347This is a part of _producer-consumer_ pattern that is often found in concurrent code.
Roman Elizarovb7721cf2017-02-03 19:23:08 +03001348You 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 +03001349to common sense that results must be returned from functions.
1350
Roman Elizarov86349be2017-03-17 16:47:37 +03001351There 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 +03001352and an extension function [consumeEach], that replaces a `for` loop on the consumer side:
Roman Elizarovb7721cf2017-02-03 19:23:08 +03001353
1354```kotlin
Roman Elizarov66f018c2017-09-29 21:39:03 +03001355fun produceSquares() = produce<Int> {
Roman Elizarovb7721cf2017-02-03 19:23:08 +03001356 for (x in 1..5) send(x * x)
1357}
1358
1359fun main(args: Array<String>) = runBlocking<Unit> {
1360 val squares = produceSquares()
Roman Elizarov86349be2017-03-17 16:47:37 +03001361 squares.consumeEach { println(it) }
Roman Elizarovb7721cf2017-02-03 19:23:08 +03001362 println("Done!")
1363}
1364```
1365
Roman Elizarove8d79342017-08-29 15:21:21 +03001366> 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 +03001367
Roman Elizarov731f0ad2017-02-22 20:48:45 +03001368<!--- TEST
13691
13704
13719
137216
137325
1374Done!
1375-->
1376
Roman Elizarovb7721cf2017-02-03 19:23:08 +03001377### Pipelines
1378
Roman Elizarov66f018c2017-09-29 21:39:03 +03001379A pipeline is a pattern where one coroutine is producing, possibly infinite, stream of values:
Roman Elizarovb7721cf2017-02-03 19:23:08 +03001380
1381```kotlin
Roman Elizarov66f018c2017-09-29 21:39:03 +03001382fun produceNumbers() = produce<Int> {
Roman Elizarovb7721cf2017-02-03 19:23:08 +03001383 var x = 1
1384 while (true) send(x++) // infinite stream of integers starting from 1
1385}
1386```
1387
Roman Elizarova5e653f2017-02-13 13:49:55 +03001388And another coroutine or coroutines are consuming that stream, doing some processing, and producing some other results.
Roman Elizarovb7721cf2017-02-03 19:23:08 +03001389In the below example the numbers are just squared:
1390
1391```kotlin
Roman Elizarov66f018c2017-09-29 21:39:03 +03001392fun square(numbers: ReceiveChannel<Int>) = produce<Int> {
Roman Elizarovb7721cf2017-02-03 19:23:08 +03001393 for (x in numbers) send(x * x)
1394}
1395```
1396
Roman Elizarova5e653f2017-02-13 13:49:55 +03001397The main code starts and connects the whole pipeline:
Roman Elizarovb7721cf2017-02-03 19:23:08 +03001398
1399```kotlin
1400fun main(args: Array<String>) = runBlocking<Unit> {
1401 val numbers = produceNumbers() // produces integers from 1 and on
1402 val squares = square(numbers) // squares integers
1403 for (i in 1..5) println(squares.receive()) // print first five
1404 println("Done!") // we are done
1405 squares.cancel() // need to cancel these coroutines in a larger app
1406 numbers.cancel()
1407}
1408```
1409
Roman Elizarove8d79342017-08-29 15:21:21 +03001410> 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 +03001411
Roman Elizarov731f0ad2017-02-22 20:48:45 +03001412<!--- TEST
14131
14144
14159
141616
141725
1418Done!
1419-->
1420
Roman Elizarovb7721cf2017-02-03 19:23:08 +03001421We don't have to cancel these coroutines in this example app, because
1422[coroutines are like daemon threads](#coroutines-are-like-daemon-threads),
1423but in a larger app we'll need to stop our pipeline if we don't need it anymore.
1424Alternatively, we could have run pipeline coroutines as
Roman Elizarov66f018c2017-09-29 21:39:03 +03001425[children of a main coroutine](#children-of-a-coroutine) as is demonstrated in the following example.
Roman Elizarovb7721cf2017-02-03 19:23:08 +03001426
1427### Prime numbers with pipeline
1428
Cedric Beustfa0b28f2017-02-07 07:07:25 -08001429Let's take pipelines to the extreme with an example that generates prime numbers using a pipeline
Roman Elizarovb7721cf2017-02-03 19:23:08 +03001430of coroutines. We start with an infinite sequence of numbers. This time we introduce an
Roman Elizarov66f018c2017-09-29 21:39:03 +03001431explicit `context` parameter and pass it to [produce] builder,
1432so that caller can control where our coroutines run:
Roman Elizarovb7721cf2017-02-03 19:23:08 +03001433
Roman Elizarov9fe5f462018-02-21 19:05:52 +03001434<!--- INCLUDE
1435import kotlin.coroutines.experimental.*
Roman Elizarovb7721cf2017-02-03 19:23:08 +03001436-->
1437
1438```kotlin
Roman Elizarova5e653f2017-02-13 13:49:55 +03001439fun numbersFrom(context: CoroutineContext, start: Int) = produce<Int>(context) {
Roman Elizarovb7721cf2017-02-03 19:23:08 +03001440 var x = start
1441 while (true) send(x++) // infinite stream of integers from start
1442}
1443```
1444
1445The following pipeline stage filters an incoming stream of numbers, removing all the numbers
1446that are divisible by the given prime number:
1447
1448```kotlin
Roman Elizarova5e653f2017-02-13 13:49:55 +03001449fun filter(context: CoroutineContext, numbers: ReceiveChannel<Int>, prime: Int) = produce<Int>(context) {
Roman Elizarovb7721cf2017-02-03 19:23:08 +03001450 for (x in numbers) if (x % prime != 0) send(x)
1451}
1452```
1453
1454Now 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 +03001455and launching new pipeline stage for each prime number found:
1456
1457```
Roman Elizarova5e653f2017-02-13 13:49:55 +03001458numbersFrom(2) -> filter(2) -> filter(3) -> filter(5) -> filter(7) ...
Roman Elizarov62500ba2017-02-09 18:55:40 +03001459```
1460
1461The following example prints the first ten prime numbers,
Roman Elizarov8b38fa22017-09-27 17:44:31 +03001462running the whole pipeline in the context of the main thread. Since all the coroutines are launched as
Roman Elizarov9fe5f462018-02-21 19:05:52 +03001463children of the main [runBlocking] coroutine in its
1464[coroutineContext](https://kotlinlang.org/api/latest/jvm/stdlib/kotlin.coroutines.experimental/coroutine-context.html),
1465we don't have to keep an explicit list of all the coroutines we have started.
Roman Elizarov3e387b82017-12-04 13:49:11 +03001466We use [cancelChildren][kotlin.coroutines.experimental.CoroutineContext.cancelChildren]
1467extension function to cancel all the children coroutines.
Roman Elizarovb7721cf2017-02-03 19:23:08 +03001468
1469```kotlin
1470fun main(args: Array<String>) = runBlocking<Unit> {
Roman Elizarov43e3af72017-07-21 16:01:31 +03001471 var cur = numbersFrom(coroutineContext, 2)
Roman Elizarovb7721cf2017-02-03 19:23:08 +03001472 for (i in 1..10) {
1473 val prime = cur.receive()
1474 println(prime)
Roman Elizarov43e3af72017-07-21 16:01:31 +03001475 cur = filter(coroutineContext, cur, prime)
Roman Elizarovb7721cf2017-02-03 19:23:08 +03001476 }
Roman Elizarov8b38fa22017-09-27 17:44:31 +03001477 coroutineContext.cancelChildren() // cancel all children to let main finish
Roman Elizarovb7721cf2017-02-03 19:23:08 +03001478}
1479```
1480
Roman Elizarove8d79342017-08-29 15:21:21 +03001481> 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 +03001482
1483The output of this code is:
1484
Roman Elizarov731f0ad2017-02-22 20:48:45 +03001485```text
Roman Elizarovb7721cf2017-02-03 19:23:08 +030014862
14873
14885
14897
149011
149113
149217
149319
149423
149529
1496```
1497
Roman Elizarov731f0ad2017-02-22 20:48:45 +03001498<!--- TEST -->
1499
Roman Elizarov66f018c2017-09-29 21:39:03 +03001500Note, that you can build the same pipeline using
1501[`buildIterator`](https://kotlinlang.org/api/latest/jvm/stdlib/kotlin.coroutines.experimental/build-iterator.html)
1502coroutine builder from the standard library.
Roman Elizarova5e653f2017-02-13 13:49:55 +03001503Replace `produce` with `buildIterator`, `send` with `yield`, `receive` with `next`,
Roman Elizarov62500ba2017-02-09 18:55:40 +03001504`ReceiveChannel` with `Iterator`, and get rid of the context. You will not need `runBlocking` either.
1505However, the benefit of a pipeline that uses channels as shown above is that it can actually use
1506multiple CPU cores if you run it in [CommonPool] context.
1507
Roman Elizarova5e653f2017-02-13 13:49:55 +03001508Anyway, this is an extremely impractical way to find prime numbers. In practice, pipelines do involve some
Roman Elizarov62500ba2017-02-09 18:55:40 +03001509other suspending invocations (like asynchronous calls to remote services) and these pipelines cannot be
1510built using `buildSeqeunce`/`buildIterator`, because they do not allow arbitrary suspension, unlike
Roman Elizarov66f018c2017-09-29 21:39:03 +03001511`produce`, which is fully asynchronous.
Roman Elizarov62500ba2017-02-09 18:55:40 +03001512
Roman Elizarovb7721cf2017-02-03 19:23:08 +03001513### Fan-out
1514
1515Multiple coroutines may receive from the same channel, distributing work between themselves.
1516Let us start with a producer coroutine that is periodically producing integers
1517(ten numbers per second):
1518
1519```kotlin
Roman Elizarov66f018c2017-09-29 21:39:03 +03001520fun produceNumbers() = produce<Int> {
Roman Elizarovb7721cf2017-02-03 19:23:08 +03001521 var x = 1 // start from 1
1522 while (true) {
1523 send(x++) // produce next
1524 delay(100) // wait 0.1s
1525 }
1526}
1527```
1528
1529Then we can have several processor coroutines. In this example, they just print their id and
1530received number:
1531
1532```kotlin
Roman Elizarov66f018c2017-09-29 21:39:03 +03001533fun launchProcessor(id: Int, channel: ReceiveChannel<Int>) = launch {
Roman Elizarov86349be2017-03-17 16:47:37 +03001534 channel.consumeEach {
1535 println("Processor #$id received $it")
Roman Elizarovec9384c2017-03-02 22:09:08 +03001536 }
Roman Elizarovb7721cf2017-02-03 19:23:08 +03001537}
1538```
1539
Roman Elizarov35d2c342017-07-20 14:54:39 +03001540Now let us launch five processors and let them work for almost a second. See what happens:
Roman Elizarovb7721cf2017-02-03 19:23:08 +03001541
1542```kotlin
1543fun main(args: Array<String>) = runBlocking<Unit> {
1544 val producer = produceNumbers()
1545 repeat(5) { launchProcessor(it, producer) }
Roman Elizarov35d2c342017-07-20 14:54:39 +03001546 delay(950)
Roman Elizarovb7721cf2017-02-03 19:23:08 +03001547 producer.cancel() // cancel producer coroutine and thus kill them all
1548}
1549```
1550
Roman Elizarove8d79342017-08-29 15:21:21 +03001551> 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 +03001552
1553The output will be similar to the the following one, albeit the processor ids that receive
1554each specific integer may be different:
1555
1556```
1557Processor #2 received 1
1558Processor #4 received 2
1559Processor #0 received 3
1560Processor #1 received 4
1561Processor #3 received 5
1562Processor #2 received 6
1563Processor #4 received 7
1564Processor #0 received 8
1565Processor #1 received 9
1566Processor #3 received 10
1567```
1568
Roman Elizarov731f0ad2017-02-22 20:48:45 +03001569<!--- TEST lines.size == 10 && lines.withIndex().all { (i, line) -> line.startsWith("Processor #") && line.endsWith(" received ${i + 1}") } -->
1570
Roman Elizarovb7721cf2017-02-03 19:23:08 +03001571Note, that cancelling a producer coroutine closes its channel, thus eventually terminating iteration
1572over the channel that processor coroutines are doing.
1573
1574### Fan-in
1575
1576Multiple coroutines may send to the same channel.
1577For example, let us have a channel of strings, and a suspending function that
1578repeatedly sends a specified string to this channel with a specified delay:
1579
Roman Elizarov9fe5f462018-02-21 19:05:52 +03001580<!--- INCLUDE
1581import kotlin.coroutines.experimental.*
1582-->
1583
Roman Elizarovb7721cf2017-02-03 19:23:08 +03001584```kotlin
1585suspend fun sendString(channel: SendChannel<String>, s: String, time: Long) {
1586 while (true) {
1587 delay(time)
1588 channel.send(s)
1589 }
1590}
1591```
1592
Cedric Beustfa0b28f2017-02-07 07:07:25 -08001593Now, let us see what happens if we launch a couple of coroutines sending strings
Roman Elizarov8b38fa22017-09-27 17:44:31 +03001594(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 +03001595
1596```kotlin
1597fun main(args: Array<String>) = runBlocking<Unit> {
1598 val channel = Channel<String>()
Roman Elizarov43e3af72017-07-21 16:01:31 +03001599 launch(coroutineContext) { sendString(channel, "foo", 200L) }
1600 launch(coroutineContext) { sendString(channel, "BAR!", 500L) }
Roman Elizarovb7721cf2017-02-03 19:23:08 +03001601 repeat(6) { // receive first six
1602 println(channel.receive())
1603 }
Roman Elizarov8b38fa22017-09-27 17:44:31 +03001604 coroutineContext.cancelChildren() // cancel all children to let main finish
Roman Elizarovb7721cf2017-02-03 19:23:08 +03001605}
1606```
1607
Roman Elizarove8d79342017-08-29 15:21:21 +03001608> 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 +03001609
1610The output is:
1611
Roman Elizarov731f0ad2017-02-22 20:48:45 +03001612```text
Roman Elizarovb7721cf2017-02-03 19:23:08 +03001613foo
1614foo
1615BAR!
1616foo
1617foo
1618BAR!
1619```
1620
Roman Elizarov731f0ad2017-02-22 20:48:45 +03001621<!--- TEST -->
1622
Roman Elizarovb7721cf2017-02-03 19:23:08 +03001623### Buffered channels
1624
1625The channels shown so far had no buffer. Unbuffered channels transfer elements when sender and receiver
1626meet each other (aka rendezvous). If send is invoked first, then it is suspended until receive is invoked,
1627if receive is invoked first, it is suspended until send is invoked.
Roman Elizarov419a6c82017-02-09 18:36:22 +03001628
Roman Elizarov88396732017-09-27 21:30:47 +03001629Both [Channel()] factory function and [produce] builder take an optional `capacity` parameter to
Roman Elizarovb7721cf2017-02-03 19:23:08 +03001630specify _buffer size_. Buffer allows senders to send multiple elements before suspending,
1631similar to the `BlockingQueue` with a specified capacity, which blocks when buffer is full.
1632
1633Take a look at the behavior of the following code:
1634
Roman Elizarov9fe5f462018-02-21 19:05:52 +03001635<!--- INCLUDE
1636import kotlin.coroutines.experimental.*
1637-->
1638
Roman Elizarovb7721cf2017-02-03 19:23:08 +03001639```kotlin
1640fun main(args: Array<String>) = runBlocking<Unit> {
1641 val channel = Channel<Int>(4) // create buffered channel
Roman Elizarov8b38fa22017-09-27 17:44:31 +03001642 val sender = launch(coroutineContext) { // launch sender coroutine
Roman Elizarovb7721cf2017-02-03 19:23:08 +03001643 repeat(10) {
1644 println("Sending $it") // print before sending each element
1645 channel.send(it) // will suspend when buffer is full
1646 }
1647 }
1648 // don't receive anything... just wait....
1649 delay(1000)
Roman Elizarov8b38fa22017-09-27 17:44:31 +03001650 sender.cancel() // cancel sender coroutine
Roman Elizarovb7721cf2017-02-03 19:23:08 +03001651}
1652```
1653
Roman Elizarove8d79342017-08-29 15:21:21 +03001654> 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 +03001655
1656It prints "sending" _five_ times using a buffered channel with capacity of _four_:
1657
Roman Elizarov731f0ad2017-02-22 20:48:45 +03001658```text
Roman Elizarovb7721cf2017-02-03 19:23:08 +03001659Sending 0
1660Sending 1
1661Sending 2
1662Sending 3
1663Sending 4
1664```
1665
Roman Elizarov731f0ad2017-02-22 20:48:45 +03001666<!--- TEST -->
1667
Roman Elizarovb7721cf2017-02-03 19:23:08 +03001668The 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 +03001669
Vsevolod Tolstopyatov03d2ff72018-05-29 17:28:20 +03001670### Ticker channels
Vsevolod Tolstopyatov1dbc25e2018-04-18 14:50:26 +03001671
Roman Elizarovb5328a72018-06-06 18:31:21 +03001672Ticker channel is a special rendezvous channel that produces `Unit` every time given delay passes since last consumption from this channel.
1673Though it may seem to be useless standalone, it is a useful building block to create complex time-based [produce]
1674pipelines and operators that do windowing and other time-dependend processing.
1675Ticker channel can be used in [select] to perform "on tick" action.
Vsevolod Tolstopyatov1dbc25e2018-04-18 14:50:26 +03001676
Roman Elizarovb5328a72018-06-06 18:31:21 +03001677To create such channel use a factory method [ticker].
1678To indicate that no further elements are needed use [ReceiveChannel.cancel] method on it.
Vsevolod Tolstopyatov1dbc25e2018-04-18 14:50:26 +03001679
1680Now let's see how it works in practice:
Vsevolod Tolstopyatov1dbc25e2018-04-18 14:50:26 +03001681
1682```kotlin
1683fun main(args: Array<String>) = runBlocking<Unit> {
Roman Elizarovb5328a72018-06-06 18:31:21 +03001684 val tickerChannel = ticker(delay = 100, initialDelay = 0) // create ticker channel
Vsevolod Tolstopyatov03d2ff72018-05-29 17:28:20 +03001685 var nextElement = withTimeoutOrNull(1) { tickerChannel.receive() }
1686 println("Initial element is available immediately: $nextElement") // Initial delay hasn't passed yet
Vsevolod Tolstopyatov1dbc25e2018-04-18 14:50:26 +03001687
Vsevolod Tolstopyatov03d2ff72018-05-29 17:28:20 +03001688 nextElement = withTimeoutOrNull(50) { tickerChannel.receive() } // All subsequent elements has 100ms delay
Vsevolod Tolstopyatov1dbc25e2018-04-18 14:50:26 +03001689 println("Next element is not ready in 50 ms: $nextElement")
1690
Roman Elizarovb5328a72018-06-06 18:31:21 +03001691 nextElement = withTimeoutOrNull(60) { tickerChannel.receive() }
Vsevolod Tolstopyatov1dbc25e2018-04-18 14:50:26 +03001692 println("Next element is ready in 100 ms: $nextElement")
1693
1694 // Emulate large consumption delays
Roman Elizarovb5328a72018-06-06 18:31:21 +03001695 println("Consumer pauses for 150ms")
Vsevolod Tolstopyatov1dbc25e2018-04-18 14:50:26 +03001696 delay(150)
1697 // Next element is available immediately
Vsevolod Tolstopyatov03d2ff72018-05-29 17:28:20 +03001698 nextElement = withTimeoutOrNull(1) { tickerChannel.receive() }
Vsevolod Tolstopyatov1dbc25e2018-04-18 14:50:26 +03001699 println("Next element is available immediately after large consumer delay: $nextElement")
1700 // Note that the pause between `receive` calls is taken into account and next element arrives faster
Roman Elizarovb5328a72018-06-06 18:31:21 +03001701 nextElement = withTimeoutOrNull(60) { tickerChannel.receive() }
Vsevolod Tolstopyatov1dbc25e2018-04-18 14:50:26 +03001702 println("Next element is ready in 50ms after consumer pause in 150ms: $nextElement")
1703
Vsevolod Tolstopyatov03d2ff72018-05-29 17:28:20 +03001704 tickerChannel.cancel() // indicate that no more elements are needed
Vsevolod Tolstopyatov1dbc25e2018-04-18 14:50:26 +03001705}
1706```
1707
1708> You can get full code [here](core/kotlinx-coroutines-core/src/test/kotlin/guide/example-channel-10.kt)
1709
1710It prints following lines:
1711
1712```text
1713Initial element is available immediately: kotlin.Unit
1714Next element is not ready in 50 ms: null
1715Next element is ready in 100 ms: kotlin.Unit
Roman Elizarovb5328a72018-06-06 18:31:21 +03001716Consumer pauses for 150ms
Vsevolod Tolstopyatov1dbc25e2018-04-18 14:50:26 +03001717Next element is available immediately after large consumer delay: kotlin.Unit
1718Next element is ready in 50ms after consumer pause in 150ms: kotlin.Unit
1719```
1720
1721<!--- TEST -->
1722
Roman Elizarovb5328a72018-06-06 18:31:21 +03001723Note that [ticker] is aware of possible consumer pauses and, by default, adjusts next produced element
1724delay if a pause occurs, trying to maintain a fixed rate of produced elements.
1725
1726Optionally, a `mode` parameters equal to [TickerMode.FIXED_DELAY] can be specified to maintain a fixed
1727delay between elements.
Vsevolod Tolstopyatov1dbc25e2018-04-18 14:50:26 +03001728
Roman Elizarovb0517ba2017-02-27 14:03:14 +03001729### Channels are fair
1730
1731Send and receive operations to channels are _fair_ with respect to the order of their invocation from
1732multiple coroutines. They are served in first-in first-out order, e.g. the first coroutine to invoke `receive`
1733gets the element. In the following example two coroutines "ping" and "pong" are
1734receiving the "ball" object from the shared "table" channel.
1735
Roman Elizarov9fe5f462018-02-21 19:05:52 +03001736<!--- INCLUDE
1737import kotlin.coroutines.experimental.*
1738-->
1739
Roman Elizarovb0517ba2017-02-27 14:03:14 +03001740```kotlin
1741data class Ball(var hits: Int)
1742
1743fun main(args: Array<String>) = runBlocking<Unit> {
1744 val table = Channel<Ball>() // a shared table
Roman Elizarov43e3af72017-07-21 16:01:31 +03001745 launch(coroutineContext) { player("ping", table) }
1746 launch(coroutineContext) { player("pong", table) }
Roman Elizarovb0517ba2017-02-27 14:03:14 +03001747 table.send(Ball(0)) // serve the ball
1748 delay(1000) // delay 1 second
Roman Elizarov8b38fa22017-09-27 17:44:31 +03001749 coroutineContext.cancelChildren() // game over, cancel them
Roman Elizarovb0517ba2017-02-27 14:03:14 +03001750}
1751
1752suspend fun player(name: String, table: Channel<Ball>) {
1753 for (ball in table) { // receive the ball in a loop
1754 ball.hits++
1755 println("$name $ball")
Roman Elizarovf526b132017-03-10 16:07:14 +03001756 delay(300) // wait a bit
Roman Elizarovb0517ba2017-02-27 14:03:14 +03001757 table.send(ball) // send the ball back
1758 }
1759}
1760```
1761
Roman Elizarove8d79342017-08-29 15:21:21 +03001762> 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 +03001763
1764The "ping" coroutine is started first, so it is the first one to receive the ball. Even though "ping"
1765coroutine immediately starts receiving the ball again after sending it back to the table, the ball gets
1766received by the "pong" coroutine, because it was already waiting for it:
1767
1768```text
1769ping Ball(hits=1)
1770pong Ball(hits=2)
1771ping Ball(hits=3)
1772pong Ball(hits=4)
Roman Elizarovb0517ba2017-02-27 14:03:14 +03001773```
1774
1775<!--- TEST -->
1776
Roman Elizarov8b38fa22017-09-27 17:44:31 +03001777Note, that sometimes channels may produce executions that look unfair due to the nature of the executor
1778that is being used. See [this issue](https://github.com/Kotlin/kotlinx.coroutines/issues/111) for details.
1779
Roman Elizarovf5bc0472017-02-22 11:38:13 +03001780## Shared mutable state and concurrency
1781
Roman Elizarov66f018c2017-09-29 21:39:03 +03001782Coroutines can be executed concurrently using a multi-threaded dispatcher like the default [CommonPool]. It presents
Roman Elizarovf5bc0472017-02-22 11:38:13 +03001783all the usual concurrency problems. The main problem being synchronization of access to **shared mutable state**.
1784Some solutions to this problem in the land of coroutines are similar to the solutions in the multi-threaded world,
1785but others are unique.
1786
1787### The problem
1788
Roman Elizarov1e459602017-02-27 11:05:17 +03001789Let us launch a thousand coroutines all doing the same action thousand times (for a total of a million executions).
1790We'll also measure their completion time for further comparisons:
Roman Elizarovf5bc0472017-02-22 11:38:13 +03001791
Roman Elizarov1e459602017-02-27 11:05:17 +03001792<!--- INCLUDE .*/example-sync-03.kt
Roman Elizarov9fe5f462018-02-21 19:05:52 +03001793import java.util.concurrent.atomic.*
Roman Elizarovf5bc0472017-02-22 11:38:13 +03001794-->
1795
Roman Elizarov1e459602017-02-27 11:05:17 +03001796<!--- INCLUDE .*/example-sync-06.kt
Roman Elizarov9fe5f462018-02-21 19:05:52 +03001797import kotlinx.coroutines.experimental.sync.*
Roman Elizarovf5bc0472017-02-22 11:38:13 +03001798-->
1799
Roman Elizarov1e459602017-02-27 11:05:17 +03001800<!--- INCLUDE .*/example-sync-07.kt
Roman Elizarovf5bc0472017-02-22 11:38:13 +03001801import kotlinx.coroutines.experimental.channels.*
1802-->
1803
Roman Elizarov9fe5f462018-02-21 19:05:52 +03001804<!--- INCLUDE .*/example-sync-([0-9a-z]+).kt
1805import kotlin.system.*
1806import kotlin.coroutines.experimental.*
1807-->
1808
Roman Elizarovf5bc0472017-02-22 11:38:13 +03001809```kotlin
Roman Elizarov1e459602017-02-27 11:05:17 +03001810suspend fun massiveRun(context: CoroutineContext, action: suspend () -> Unit) {
1811 val n = 1000 // number of coroutines to launch
1812 val k = 1000 // times an action is repeated by each coroutine
Roman Elizarovf5bc0472017-02-22 11:38:13 +03001813 val time = measureTimeMillis {
1814 val jobs = List(n) {
Roman Elizarov1e459602017-02-27 11:05:17 +03001815 launch(context) {
1816 repeat(k) { action() }
Roman Elizarovf5bc0472017-02-22 11:38:13 +03001817 }
1818 }
1819 jobs.forEach { it.join() }
1820 }
Roman Elizarov1e459602017-02-27 11:05:17 +03001821 println("Completed ${n * k} actions in $time ms")
Roman Elizarovf5bc0472017-02-22 11:38:13 +03001822}
1823```
1824
Roman Elizarov43e90112017-05-10 11:25:20 +03001825<!--- INCLUDE .*/example-sync-([0-9a-z]+).kt -->
Roman Elizarovf5bc0472017-02-22 11:38:13 +03001826
Roman Elizarov1e459602017-02-27 11:05:17 +03001827We start with a very simple action that increments a shared mutable variable using
1828multi-threaded [CommonPool] context.
Roman Elizarovf5bc0472017-02-22 11:38:13 +03001829
1830```kotlin
1831var counter = 0
1832
1833fun main(args: Array<String>) = runBlocking<Unit> {
Roman Elizarov1e459602017-02-27 11:05:17 +03001834 massiveRun(CommonPool) {
Roman Elizarovf5bc0472017-02-22 11:38:13 +03001835 counter++
1836 }
1837 println("Counter = $counter")
1838}
1839```
1840
Roman Elizarove8d79342017-08-29 15:21:21 +03001841> 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 +03001842
Roman Elizarov1e459602017-02-27 11:05:17 +03001843<!--- TEST LINES_START
1844Completed 1000000 actions in
1845Counter =
1846-->
Roman Elizarov731f0ad2017-02-22 20:48:45 +03001847
Roman Elizarov1e459602017-02-27 11:05:17 +03001848What does it print at the end? It is highly unlikely to ever print "Counter = 1000000", because a thousand coroutines
1849increment the `counter` concurrently from multiple threads without any synchronization.
1850
Roman Elizarov43e90112017-05-10 11:25:20 +03001851> Note: if you have an old system with 2 or fewer CPUs, then you _will_ consistently see 1000000, because
1852`CommonPool` is running in only one thread in this case. To reproduce the problem you'll need to make the
1853following change:
1854
1855```kotlin
1856val mtContext = newFixedThreadPoolContext(2, "mtPool") // explicitly define context with two threads
1857var counter = 0
1858
1859fun main(args: Array<String>) = runBlocking<Unit> {
1860 massiveRun(mtContext) { // use it instead of CommonPool in this sample and below
1861 counter++
1862 }
1863 println("Counter = $counter")
1864}
1865```
1866
Roman Elizarove8d79342017-08-29 15:21:21 +03001867> 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 +03001868
1869<!--- TEST LINES_START
1870Completed 1000000 actions in
1871Counter =
1872-->
1873
Roman Elizarov1e459602017-02-27 11:05:17 +03001874### Volatiles are of no help
1875
1876There is common misconception that making a variable `volatile` solves concurrency problem. Let us try it:
1877
1878```kotlin
1879@Volatile // in Kotlin `volatile` is an annotation
1880var counter = 0
1881
1882fun main(args: Array<String>) = runBlocking<Unit> {
1883 massiveRun(CommonPool) {
1884 counter++
1885 }
1886 println("Counter = $counter")
1887}
1888```
1889
Roman Elizarove8d79342017-08-29 15:21:21 +03001890> 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 +03001891
1892<!--- TEST LINES_START
1893Completed 1000000 actions in
1894Counter =
1895-->
1896
1897This code works slower, but we still don't get "Counter = 1000000" at the end, because volatile variables guarantee
1898linearizable (this is a technical term for "atomic") reads and writes to the corresponding variable, but
1899do not provide atomicity of larger actions (increment in our case).
Roman Elizarovf5bc0472017-02-22 11:38:13 +03001900
1901### Thread-safe data structures
1902
1903The general solution that works both for threads and for coroutines is to use a thread-safe (aka synchronized,
1904linearizable, or atomic) data structure that provides all the necessarily synchronization for the corresponding
1905operations that needs to be performed on a shared state.
Roman Elizarov1e459602017-02-27 11:05:17 +03001906In the case of a simple counter we can use `AtomicInteger` class which has atomic `incrementAndGet` operations:
Roman Elizarovf5bc0472017-02-22 11:38:13 +03001907
1908```kotlin
1909var counter = AtomicInteger()
1910
1911fun main(args: Array<String>) = runBlocking<Unit> {
Roman Elizarov1e459602017-02-27 11:05:17 +03001912 massiveRun(CommonPool) {
Roman Elizarovf5bc0472017-02-22 11:38:13 +03001913 counter.incrementAndGet()
1914 }
1915 println("Counter = ${counter.get()}")
1916}
1917```
1918
Roman Elizarove8d79342017-08-29 15:21:21 +03001919> 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 +03001920
Roman Elizarov1e459602017-02-27 11:05:17 +03001921<!--- TEST ARBITRARY_TIME
1922Completed 1000000 actions in xxx ms
1923Counter = 1000000
1924-->
Roman Elizarov731f0ad2017-02-22 20:48:45 +03001925
Roman Elizarovf5bc0472017-02-22 11:38:13 +03001926This is the fastest solution for this particular problem. It works for plain counters, collections, queues and other
1927standard data structures and basic operations on them. However, it does not easily scale to complex
1928state or to complex operations that do not have ready-to-use thread-safe implementations.
1929
Roman Elizarov1e459602017-02-27 11:05:17 +03001930### Thread confinement fine-grained
Roman Elizarovf5bc0472017-02-22 11:38:13 +03001931
Roman Elizarov1e459602017-02-27 11:05:17 +03001932_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 +03001933state is confined to a single thread. It is typically used in UI applications, where all UI state is confined to
1934the single event-dispatch/application thread. It is easy to apply with coroutines by using a
1935single-threaded context:
1936
1937```kotlin
1938val counterContext = newSingleThreadContext("CounterContext")
1939var counter = 0
1940
1941fun main(args: Array<String>) = runBlocking<Unit> {
Roman Elizarov1e459602017-02-27 11:05:17 +03001942 massiveRun(CommonPool) { // run each coroutine in CommonPool
Roman Elizarovf9e13f52017-12-21 12:23:15 +03001943 withContext(counterContext) { // but confine each increment to the single-threaded context
Roman Elizarovf5bc0472017-02-22 11:38:13 +03001944 counter++
1945 }
1946 }
1947 println("Counter = $counter")
1948}
1949```
1950
Roman Elizarove8d79342017-08-29 15:21:21 +03001951> 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 +03001952
Roman Elizarov1e459602017-02-27 11:05:17 +03001953<!--- TEST ARBITRARY_TIME
1954Completed 1000000 actions in xxx ms
1955Counter = 1000000
1956-->
1957
1958This code works very slowly, because it does _fine-grained_ thread-confinement. Each individual increment switches
Roman Elizarovf9e13f52017-12-21 12:23:15 +03001959from multi-threaded `CommonPool` context to the single-threaded context using [withContext] block.
Roman Elizarov1e459602017-02-27 11:05:17 +03001960
1961### Thread confinement coarse-grained
1962
1963In practice, thread confinement is performed in large chunks, e.g. big pieces of state-updating business logic
1964are confined to the single thread. The following example does it like that, running each coroutine in
1965the single-threaded context to start with.
1966
1967```kotlin
1968val counterContext = newSingleThreadContext("CounterContext")
1969var counter = 0
1970
1971fun main(args: Array<String>) = runBlocking<Unit> {
1972 massiveRun(counterContext) { // run each coroutine in the single-threaded context
1973 counter++
1974 }
1975 println("Counter = $counter")
1976}
1977```
1978
Roman Elizarove8d79342017-08-29 15:21:21 +03001979> 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 +03001980
1981<!--- TEST ARBITRARY_TIME
1982Completed 1000000 actions in xxx ms
1983Counter = 1000000
1984-->
1985
1986This now works much faster and produces correct result.
Roman Elizarov731f0ad2017-02-22 20:48:45 +03001987
Roman Elizarovf5bc0472017-02-22 11:38:13 +03001988### Mutual exclusion
1989
1990Mutual exclusion solution to the problem is to protect all modifications of the shared state with a _critical section_
1991that is never executed concurrently. In a blocking world you'd typically use `synchronized` or `ReentrantLock` for that.
1992Coroutine's alternative is called [Mutex]. It has [lock][Mutex.lock] and [unlock][Mutex.unlock] functions to
1993delimit a critical section. The key difference is that `Mutex.lock` is a suspending function. It does not block a thread.
1994
Roman Elizarov88396732017-09-27 21:30:47 +03001995There is also [withLock] extension function that conveniently represents
Roman Elizarov8b38fa22017-09-27 17:44:31 +03001996`mutex.lock(); try { ... } finally { mutex.unlock() }` pattern:
1997
Roman Elizarovf5bc0472017-02-22 11:38:13 +03001998```kotlin
1999val mutex = Mutex()
2000var counter = 0
2001
2002fun main(args: Array<String>) = runBlocking<Unit> {
Roman Elizarov1e459602017-02-27 11:05:17 +03002003 massiveRun(CommonPool) {
Roman Elizarov8b38fa22017-09-27 17:44:31 +03002004 mutex.withLock {
2005 counter++
2006 }
Roman Elizarovf5bc0472017-02-22 11:38:13 +03002007 }
2008 println("Counter = $counter")
2009}
2010```
2011
Roman Elizarove8d79342017-08-29 15:21:21 +03002012> 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 +03002013
Roman Elizarov1e459602017-02-27 11:05:17 +03002014<!--- TEST ARBITRARY_TIME
2015Completed 1000000 actions in xxx ms
2016Counter = 1000000
2017-->
2018
2019The locking in this example is fine-grained, so it pays the price. However, it is a good choice for some situations
2020where you absolutely must modify some shared state periodically, but there is no natural thread that this state
2021is confined to.
Roman Elizarov731f0ad2017-02-22 20:48:45 +03002022
Roman Elizarovf5bc0472017-02-22 11:38:13 +03002023### Actors
2024
2025An actor is a combination of a coroutine, the state that is confined and is encapsulated into this coroutine,
2026and a channel to communicate with other coroutines. A simple actor can be written as a function,
2027but an actor with a complex state is better suited for a class.
2028
Roman Elizarovc0e19f82017-02-27 11:59:14 +03002029There is an [actor] coroutine builder that conveniently combines actor's mailbox channel into its
2030scope to receive messages from and combines the send channel into the resulting job object, so that a
2031single reference to the actor can be carried around as its handle.
2032
Roman Elizarov256812a2017-07-22 01:00:30 +03002033The first step of using an actor is to define a class of messages that an actor is going to process.
2034Kotlin's [sealed classes](https://kotlinlang.org/docs/reference/sealed-classes.html) are well suited for that purpose.
2035We define `CounterMsg` sealed class with `IncCounter` message to increment a counter and `GetCounter` message
2036to get its value. The later needs to send a response. A [CompletableDeferred] communication
2037primitive, that represents a single value that will be known (communicated) in the future,
2038is used here for that purpose.
2039
Roman Elizarovf5bc0472017-02-22 11:38:13 +03002040```kotlin
2041// Message types for counterActor
2042sealed class CounterMsg
2043object IncCounter : CounterMsg() // one-way message to increment counter
Roman Elizarov256812a2017-07-22 01:00:30 +03002044class GetCounter(val response: CompletableDeferred<Int>) : CounterMsg() // a request with reply
2045```
Roman Elizarovf5bc0472017-02-22 11:38:13 +03002046
Roman Elizarov256812a2017-07-22 01:00:30 +03002047Then we define a function that launches an actor using an [actor] coroutine builder:
2048
2049```kotlin
Roman Elizarovf5bc0472017-02-22 11:38:13 +03002050// This function launches a new counter actor
Roman Elizarov66f018c2017-09-29 21:39:03 +03002051fun counterActor() = actor<CounterMsg> {
Roman Elizarovf5bc0472017-02-22 11:38:13 +03002052 var counter = 0 // actor state
Roman Elizarovc0e19f82017-02-27 11:59:14 +03002053 for (msg in channel) { // iterate over incoming messages
Roman Elizarovf5bc0472017-02-22 11:38:13 +03002054 when (msg) {
2055 is IncCounter -> counter++
Roman Elizarov256812a2017-07-22 01:00:30 +03002056 is GetCounter -> msg.response.complete(counter)
Roman Elizarovf5bc0472017-02-22 11:38:13 +03002057 }
2058 }
2059}
Roman Elizarov256812a2017-07-22 01:00:30 +03002060```
Roman Elizarovf5bc0472017-02-22 11:38:13 +03002061
Roman Elizarov256812a2017-07-22 01:00:30 +03002062The main code is straightforward:
2063
2064```kotlin
Roman Elizarovf5bc0472017-02-22 11:38:13 +03002065fun main(args: Array<String>) = runBlocking<Unit> {
Roman Elizarovc0e19f82017-02-27 11:59:14 +03002066 val counter = counterActor() // create the actor
Roman Elizarov1e459602017-02-27 11:05:17 +03002067 massiveRun(CommonPool) {
Roman Elizarovc0e19f82017-02-27 11:59:14 +03002068 counter.send(IncCounter)
Roman Elizarovf5bc0472017-02-22 11:38:13 +03002069 }
Roman Elizarov256812a2017-07-22 01:00:30 +03002070 // send a message to get a counter value from an actor
2071 val response = CompletableDeferred<Int>()
Roman Elizarovc0e19f82017-02-27 11:59:14 +03002072 counter.send(GetCounter(response))
Roman Elizarov256812a2017-07-22 01:00:30 +03002073 println("Counter = ${response.await()}")
Roman Elizarovc0e19f82017-02-27 11:59:14 +03002074 counter.close() // shutdown the actor
Roman Elizarovf5bc0472017-02-22 11:38:13 +03002075}
2076```
2077
Roman Elizarove8d79342017-08-29 15:21:21 +03002078> 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 +03002079
Roman Elizarov1e459602017-02-27 11:05:17 +03002080<!--- TEST ARBITRARY_TIME
2081Completed 1000000 actions in xxx ms
2082Counter = 1000000
2083-->
Roman Elizarov731f0ad2017-02-22 20:48:45 +03002084
Roman Elizarovc0e19f82017-02-27 11:59:14 +03002085It does not matter (for correctness) what context the actor itself is executed in. An actor is
Roman Elizarovf5bc0472017-02-22 11:38:13 +03002086a coroutine and a coroutine is executed sequentially, so confinement of the state to the specific coroutine
2087works as a solution to the problem of shared mutable state.
2088
Roman Elizarovc0e19f82017-02-27 11:59:14 +03002089Actor is more efficient than locking under load, because in this case it always has work to do and it does not
2090have to switch to a different context at all.
2091
2092> Note, that an [actor] coroutine builder is a dual of [produce] coroutine builder. An actor is associated
2093 with the channel that it receives messages from, while a producer is associated with the channel that it
2094 sends elements to.
Roman Elizarov1e459602017-02-27 11:05:17 +03002095
Roman Elizarovd4dcbe22017-02-22 09:57:46 +03002096## Select expression
2097
Roman Elizarova84730b2017-02-22 11:58:50 +03002098Select expression makes it possible to await multiple suspending functions simultaneously and _select_
Roman Elizarovd4dcbe22017-02-22 09:57:46 +03002099the first one that becomes available.
2100
2101<!--- INCLUDE .*/example-select-([0-9]+).kt
2102import kotlinx.coroutines.experimental.channels.*
2103import kotlinx.coroutines.experimental.selects.*
2104-->
2105
2106### Selecting from channels
2107
Roman Elizarov57857202017-03-02 23:17:25 +03002108Let us have two producers of strings: `fizz` and `buzz`. The `fizz` produces "Fizz" string every 300 ms:
2109
Roman Elizarov9fe5f462018-02-21 19:05:52 +03002110<!--- INCLUDE
2111import kotlinx.coroutines.experimental.*
2112import kotlin.coroutines.experimental.*
Roman Elizarov57857202017-03-02 23:17:25 +03002113-->
2114
Roman Elizarovd4dcbe22017-02-22 09:57:46 +03002115```kotlin
Roman Elizarov57857202017-03-02 23:17:25 +03002116fun fizz(context: CoroutineContext) = produce<String>(context) {
2117 while (true) { // sends "Fizz" every 300 ms
Roman Elizarovd4dcbe22017-02-22 09:57:46 +03002118 delay(300)
2119 send("Fizz")
2120 }
2121}
2122```
2123
Roman Elizarov57857202017-03-02 23:17:25 +03002124And the `buzz` produces "Buzz!" string every 500 ms:
Roman Elizarovd4dcbe22017-02-22 09:57:46 +03002125
2126```kotlin
Roman Elizarov57857202017-03-02 23:17:25 +03002127fun buzz(context: CoroutineContext) = produce<String>(context) {
2128 while (true) { // sends "Buzz!" every 500 ms
Roman Elizarovd4dcbe22017-02-22 09:57:46 +03002129 delay(500)
2130 send("Buzz!")
2131 }
2132}
2133```
2134
2135Using [receive][ReceiveChannel.receive] suspending function we can receive _either_ from one channel or the
2136other. But [select] expression allows us to receive from _both_ simultaneously using its
Roman Elizarov8a5564d2017-09-06 18:48:22 +03002137[onReceive][ReceiveChannel.onReceive] clauses:
Roman Elizarovd4dcbe22017-02-22 09:57:46 +03002138
2139```kotlin
Roman Elizarov57857202017-03-02 23:17:25 +03002140suspend fun selectFizzBuzz(fizz: ReceiveChannel<String>, buzz: ReceiveChannel<String>) {
Roman Elizarovd4dcbe22017-02-22 09:57:46 +03002141 select<Unit> { // <Unit> means that this select expression does not produce any result
2142 fizz.onReceive { value -> // this is the first select clause
2143 println("fizz -> '$value'")
2144 }
2145 buzz.onReceive { value -> // this is the second select clause
2146 println("buzz -> '$value'")
2147 }
2148 }
2149}
2150```
2151
Roman Elizarov57857202017-03-02 23:17:25 +03002152Let us run it all seven times:
Roman Elizarovd4dcbe22017-02-22 09:57:46 +03002153
2154```kotlin
2155fun main(args: Array<String>) = runBlocking<Unit> {
Roman Elizarov43e3af72017-07-21 16:01:31 +03002156 val fizz = fizz(coroutineContext)
2157 val buzz = buzz(coroutineContext)
Roman Elizarovd4dcbe22017-02-22 09:57:46 +03002158 repeat(7) {
Roman Elizarov57857202017-03-02 23:17:25 +03002159 selectFizzBuzz(fizz, buzz)
Roman Elizarovd4dcbe22017-02-22 09:57:46 +03002160 }
Roman Elizarov8b38fa22017-09-27 17:44:31 +03002161 coroutineContext.cancelChildren() // cancel fizz & buzz coroutines
Roman Elizarovd4dcbe22017-02-22 09:57:46 +03002162}
2163```
2164
Roman Elizarove8d79342017-08-29 15:21:21 +03002165> 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 +03002166
2167The result of this code is:
2168
Roman Elizarov731f0ad2017-02-22 20:48:45 +03002169```text
Roman Elizarovd4dcbe22017-02-22 09:57:46 +03002170fizz -> 'Fizz'
2171buzz -> 'Buzz!'
2172fizz -> 'Fizz'
2173fizz -> 'Fizz'
2174buzz -> 'Buzz!'
2175fizz -> 'Fizz'
2176buzz -> 'Buzz!'
2177```
2178
Roman Elizarov731f0ad2017-02-22 20:48:45 +03002179<!--- TEST -->
2180
Roman Elizarovd4dcbe22017-02-22 09:57:46 +03002181### Selecting on close
2182
Roman Elizarov8a5564d2017-09-06 18:48:22 +03002183The [onReceive][ReceiveChannel.onReceive] clause in `select` fails when the channel is closed and the corresponding
2184`select` throws an exception. We can use [onReceiveOrNull][ReceiveChannel.onReceiveOrNull] clause to perform a
Roman Elizarova84730b2017-02-22 11:58:50 +03002185specific 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 +03002186the result of its selected clause:
2187
Roman Elizarov9fe5f462018-02-21 19:05:52 +03002188<!--- INCLUDE
2189import kotlin.coroutines.experimental.*
2190-->
2191
Roman Elizarovd4dcbe22017-02-22 09:57:46 +03002192```kotlin
2193suspend fun selectAorB(a: ReceiveChannel<String>, b: ReceiveChannel<String>): String =
2194 select<String> {
2195 a.onReceiveOrNull { value ->
2196 if (value == null)
2197 "Channel 'a' is closed"
2198 else
2199 "a -> '$value'"
2200 }
2201 b.onReceiveOrNull { value ->
2202 if (value == null)
2203 "Channel 'b' is closed"
2204 else
2205 "b -> '$value'"
2206 }
2207 }
2208```
2209
Roman Elizarova84730b2017-02-22 11:58:50 +03002210Let's use it with channel `a` that produces "Hello" string four times and
2211channel `b` that produces "World" four times:
Roman Elizarovd4dcbe22017-02-22 09:57:46 +03002212
2213```kotlin
2214fun main(args: Array<String>) = runBlocking<Unit> {
2215 // we are using the context of the main thread in this example for predictability ...
Roman Elizarov43e3af72017-07-21 16:01:31 +03002216 val a = produce<String>(coroutineContext) {
Roman Elizarova84730b2017-02-22 11:58:50 +03002217 repeat(4) { send("Hello $it") }
Roman Elizarovd4dcbe22017-02-22 09:57:46 +03002218 }
Roman Elizarov43e3af72017-07-21 16:01:31 +03002219 val b = produce<String>(coroutineContext) {
Roman Elizarova84730b2017-02-22 11:58:50 +03002220 repeat(4) { send("World $it") }
Roman Elizarovd4dcbe22017-02-22 09:57:46 +03002221 }
2222 repeat(8) { // print first eight results
2223 println(selectAorB(a, b))
2224 }
Roman Elizarov8b38fa22017-09-27 17:44:31 +03002225 coroutineContext.cancelChildren()
Roman Elizarovd4dcbe22017-02-22 09:57:46 +03002226}
2227```
2228
Roman Elizarove8d79342017-08-29 15:21:21 +03002229> 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 +03002230
Roman Elizarova84730b2017-02-22 11:58:50 +03002231The result of this code is quite interesting, so we'll analyze it in mode detail:
Roman Elizarovd4dcbe22017-02-22 09:57:46 +03002232
Roman Elizarov731f0ad2017-02-22 20:48:45 +03002233```text
Roman Elizarovd4dcbe22017-02-22 09:57:46 +03002234a -> 'Hello 0'
2235a -> 'Hello 1'
2236b -> 'World 0'
2237a -> 'Hello 2'
2238a -> 'Hello 3'
2239b -> 'World 1'
2240Channel 'a' is closed
2241Channel 'a' is closed
2242```
2243
Roman Elizarov731f0ad2017-02-22 20:48:45 +03002244<!--- TEST -->
2245
Roman Elizarova84730b2017-02-22 11:58:50 +03002246There are couple of observations to make out of it.
Roman Elizarovd4dcbe22017-02-22 09:57:46 +03002247
2248First of all, `select` is _biased_ to the first clause. When several clauses are selectable at the same time,
2249the first one among them gets selected. Here, both channels are constantly producing strings, so `a` channel,
Roman Elizarova84730b2017-02-22 11:58:50 +03002250being 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 +03002251time to time on its [send][SendChannel.send] invocation and gives a chance for `b` to send, too.
2252
Roman Elizarov8a5564d2017-09-06 18:48:22 +03002253The second observation, is that [onReceiveOrNull][ReceiveChannel.onReceiveOrNull] gets immediately selected when the
Roman Elizarovd4dcbe22017-02-22 09:57:46 +03002254channel is already closed.
2255
2256### Selecting to send
2257
Roman Elizarov8a5564d2017-09-06 18:48:22 +03002258Select expression has [onSend][SendChannel.onSend] clause that can be used for a great good in combination
Roman Elizarovd4dcbe22017-02-22 09:57:46 +03002259with a biased nature of selection.
2260
Roman Elizarova84730b2017-02-22 11:58:50 +03002261Let us write an example of producer of integers that sends its values to a `side` channel when
Roman Elizarovd4dcbe22017-02-22 09:57:46 +03002262the consumers on its primary channel cannot keep up with it:
2263
Roman Elizarov8b38fa22017-09-27 17:44:31 +03002264<!--- INCLUDE
Roman Elizarov9fe5f462018-02-21 19:05:52 +03002265import kotlin.coroutines.experimental.*
Roman Elizarov8b38fa22017-09-27 17:44:31 +03002266-->
2267
Roman Elizarovd4dcbe22017-02-22 09:57:46 +03002268```kotlin
Roman Elizarov8b38fa22017-09-27 17:44:31 +03002269fun produceNumbers(context: CoroutineContext, side: SendChannel<Int>) = produce<Int>(context) {
Roman Elizarovd4dcbe22017-02-22 09:57:46 +03002270 for (num in 1..10) { // produce 10 numbers from 1 to 10
2271 delay(100) // every 100 ms
2272 select<Unit> {
Roman Elizarova84730b2017-02-22 11:58:50 +03002273 onSend(num) {} // Send to the primary channel
2274 side.onSend(num) {} // or to the side channel
Roman Elizarovd4dcbe22017-02-22 09:57:46 +03002275 }
2276 }
2277}
2278```
2279
2280Consumer is going to be quite slow, taking 250 ms to process each number:
Roman Elizarov9fe5f462018-02-21 19:05:52 +03002281
Roman Elizarovd4dcbe22017-02-22 09:57:46 +03002282```kotlin
2283fun main(args: Array<String>) = runBlocking<Unit> {
2284 val side = Channel<Int>() // allocate side channel
Roman Elizarov43e3af72017-07-21 16:01:31 +03002285 launch(coroutineContext) { // this is a very fast consumer for the side channel
Roman Elizarov86349be2017-03-17 16:47:37 +03002286 side.consumeEach { println("Side channel has $it") }
Roman Elizarovd4dcbe22017-02-22 09:57:46 +03002287 }
Roman Elizarov8b38fa22017-09-27 17:44:31 +03002288 produceNumbers(coroutineContext, side).consumeEach {
Roman Elizarov86349be2017-03-17 16:47:37 +03002289 println("Consuming $it")
Roman Elizarovd4dcbe22017-02-22 09:57:46 +03002290 delay(250) // let us digest the consumed number properly, do not hurry
2291 }
2292 println("Done consuming")
Roman Elizarov8b38fa22017-09-27 17:44:31 +03002293 coroutineContext.cancelChildren()
Roman Elizarovd4dcbe22017-02-22 09:57:46 +03002294}
2295```
2296
Roman Elizarove8d79342017-08-29 15:21:21 +03002297> 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 +03002298
2299So let us see what happens:
2300
Roman Elizarov731f0ad2017-02-22 20:48:45 +03002301```text
Roman Elizarovd4dcbe22017-02-22 09:57:46 +03002302Consuming 1
2303Side channel has 2
2304Side channel has 3
2305Consuming 4
2306Side channel has 5
2307Side channel has 6
2308Consuming 7
2309Side channel has 8
2310Side channel has 9
2311Consuming 10
2312Done consuming
2313```
2314
Roman Elizarov731f0ad2017-02-22 20:48:45 +03002315<!--- TEST -->
2316
Roman Elizarovd4dcbe22017-02-22 09:57:46 +03002317### Selecting deferred values
2318
Roman Elizarov8a5564d2017-09-06 18:48:22 +03002319Deferred values can be selected using [onAwait][Deferred.onAwait] clause.
Roman Elizarova84730b2017-02-22 11:58:50 +03002320Let us start with an async function that returns a deferred string value after
Roman Elizarovd4dcbe22017-02-22 09:57:46 +03002321a random delay:
2322
2323<!--- INCLUDE .*/example-select-04.kt
2324import java.util.*
2325-->
2326
2327```kotlin
Roman Elizarov66f018c2017-09-29 21:39:03 +03002328fun asyncString(time: Int) = async {
Roman Elizarovd4dcbe22017-02-22 09:57:46 +03002329 delay(time.toLong())
2330 "Waited for $time ms"
2331}
2332```
2333
Roman Elizarova84730b2017-02-22 11:58:50 +03002334Let us start a dozen of them with a random delay.
Roman Elizarovd4dcbe22017-02-22 09:57:46 +03002335
2336```kotlin
2337fun asyncStringsList(): List<Deferred<String>> {
2338 val random = Random(3)
Roman Elizarova84730b2017-02-22 11:58:50 +03002339 return List(12) { asyncString(random.nextInt(1000)) }
Roman Elizarovd4dcbe22017-02-22 09:57:46 +03002340}
2341```
2342
Roman Elizarova84730b2017-02-22 11:58:50 +03002343Now 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 +03002344that 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 +03002345so we can provide clauses for it using an arbitrary code. In this case we iterate over a list
2346of deferred values to provide `onAwait` clause for each deferred value.
Roman Elizarovd4dcbe22017-02-22 09:57:46 +03002347
2348```kotlin
2349fun main(args: Array<String>) = runBlocking<Unit> {
2350 val list = asyncStringsList()
2351 val result = select<String> {
2352 list.withIndex().forEach { (index, deferred) ->
2353 deferred.onAwait { answer ->
2354 "Deferred $index produced answer '$answer'"
2355 }
2356 }
2357 }
2358 println(result)
Roman Elizarov7c864d82017-02-27 10:17:50 +03002359 val countActive = list.count { it.isActive }
Roman Elizarovd4dcbe22017-02-22 09:57:46 +03002360 println("$countActive coroutines are still active")
2361}
2362```
2363
Roman Elizarove8d79342017-08-29 15:21:21 +03002364> 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 +03002365
2366The output is:
2367
Roman Elizarov731f0ad2017-02-22 20:48:45 +03002368```text
Roman Elizarova84730b2017-02-22 11:58:50 +03002369Deferred 4 produced answer 'Waited for 128 ms'
Roman Elizarovd4dcbe22017-02-22 09:57:46 +0300237011 coroutines are still active
2371```
2372
Roman Elizarov731f0ad2017-02-22 20:48:45 +03002373<!--- TEST -->
2374
Roman Elizarovd4dcbe22017-02-22 09:57:46 +03002375### Switch over a channel of deferred values
2376
Roman Elizarova84730b2017-02-22 11:58:50 +03002377Let us write a channel producer function that consumes a channel of deferred string values, waits for each received
2378deferred 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 +03002379[onReceiveOrNull][ReceiveChannel.onReceiveOrNull] and [onAwait][Deferred.onAwait] clauses in the same `select`:
Roman Elizarovd4dcbe22017-02-22 09:57:46 +03002380
Roman Elizarov9fe5f462018-02-21 19:05:52 +03002381<!--- INCLUDE
2382import kotlin.coroutines.experimental.*
2383-->
2384
Roman Elizarovd4dcbe22017-02-22 09:57:46 +03002385```kotlin
Roman Elizarov66f018c2017-09-29 21:39:03 +03002386fun switchMapDeferreds(input: ReceiveChannel<Deferred<String>>) = produce<String> {
Roman Elizarova84730b2017-02-22 11:58:50 +03002387 var current = input.receive() // start with first received deferred value
Roman Elizarovd4dcbe22017-02-22 09:57:46 +03002388 while (isActive) { // loop while not cancelled/closed
2389 val next = select<Deferred<String>?> { // return next deferred value from this select or null
2390 input.onReceiveOrNull { update ->
2391 update // replaces next value to wait
2392 }
2393 current.onAwait { value ->
2394 send(value) // send value that current deferred has produced
2395 input.receiveOrNull() // and use the next deferred from the input channel
2396 }
2397 }
2398 if (next == null) {
2399 println("Channel was closed")
2400 break // out of loop
2401 } else {
2402 current = next
2403 }
2404 }
2405}
2406```
2407
2408To test it, we'll use a simple async function that resolves to a specified string after a specified time:
2409
2410```kotlin
Roman Elizarov66f018c2017-09-29 21:39:03 +03002411fun asyncString(str: String, time: Long) = async {
Roman Elizarovd4dcbe22017-02-22 09:57:46 +03002412 delay(time)
2413 str
2414}
2415```
2416
2417The main function just launches a coroutine to print results of `switchMapDeferreds` and sends some test
2418data to it:
2419
2420```kotlin
2421fun main(args: Array<String>) = runBlocking<Unit> {
2422 val chan = Channel<Deferred<String>>() // the channel for test
Roman Elizarov43e3af72017-07-21 16:01:31 +03002423 launch(coroutineContext) { // launch printing coroutine
Roman Elizarovd4dcbe22017-02-22 09:57:46 +03002424 for (s in switchMapDeferreds(chan))
2425 println(s) // print each received string
2426 }
2427 chan.send(asyncString("BEGIN", 100))
2428 delay(200) // enough time for "BEGIN" to be produced
2429 chan.send(asyncString("Slow", 500))
Roman Elizarova84730b2017-02-22 11:58:50 +03002430 delay(100) // not enough time to produce slow
Roman Elizarovd4dcbe22017-02-22 09:57:46 +03002431 chan.send(asyncString("Replace", 100))
Roman Elizarova84730b2017-02-22 11:58:50 +03002432 delay(500) // give it time before the last one
Roman Elizarovd4dcbe22017-02-22 09:57:46 +03002433 chan.send(asyncString("END", 500))
2434 delay(1000) // give it time to process
Roman Elizarova84730b2017-02-22 11:58:50 +03002435 chan.close() // close the channel ...
Roman Elizarovd4dcbe22017-02-22 09:57:46 +03002436 delay(500) // and wait some time to let it finish
2437}
2438```
2439
Roman Elizarove8d79342017-08-29 15:21:21 +03002440> 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 +03002441
2442The result of this code:
2443
Roman Elizarov731f0ad2017-02-22 20:48:45 +03002444```text
Roman Elizarovd4dcbe22017-02-22 09:57:46 +03002445BEGIN
2446Replace
2447END
2448Channel was closed
2449```
2450
Roman Elizarov731f0ad2017-02-22 20:48:45 +03002451<!--- TEST -->
Roman Elizarovd4dcbe22017-02-22 09:57:46 +03002452
Roman Elizarov8db17332017-03-09 12:40:45 +03002453## Further reading
2454
2455* [Guide to UI programming with coroutines](ui/coroutines-guide-ui.md)
Roman Elizarov8a4a8e12017-03-09 19:52:58 +03002456* [Guide to reactive streams with coroutines](reactive/coroutines-guide-reactive.md)
Roman Elizarov8db17332017-03-09 12:40:45 +03002457* [Coroutines design document (KEEP)](https://github.com/Kotlin/kotlin-coroutines/blob/master/kotlin-coroutines-informal.md)
2458* [Full kotlinx.coroutines API reference](http://kotlin.github.io/kotlinx.coroutines)
2459
Roman Elizarove7e2ad12017-05-17 14:47:31 +03002460<!--- MODULE kotlinx-coroutines-core -->
Roman Elizarove0c817d2017-02-10 10:22:01 +03002461<!--- INDEX kotlinx.coroutines.experimental -->
Roman Elizarovd4dcbe22017-02-22 09:57:46 +03002462[launch]: https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines.experimental/launch.html
2463[delay]: https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines.experimental/delay.html
2464[runBlocking]: https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines.experimental/run-blocking.html
Roman Elizarove82dee72017-08-18 16:49:09 +03002465[Job]: https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines.experimental/-job/index.html
Roman Elizarov8b38fa22017-09-27 17:44:31 +03002466[cancelAndJoin]: https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines.experimental/cancel-and-join.html
Roman Elizarov88396732017-09-27 21:30:47 +03002467[Job.cancel]: https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines.experimental/-job/cancel.html
2468[Job.join]: https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines.experimental/-job/join.html
Roman Elizarovcbb602d2017-12-23 14:24:26 +03002469[CancellationException]: https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines.experimental/-cancellation-exception/index.html
Roman Elizarovd4dcbe22017-02-22 09:57:46 +03002470[yield]: https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines.experimental/yield.html
Roman Elizarovbff3f372017-03-01 18:12:27 +03002471[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 +03002472[CoroutineScope]: https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines.experimental/-coroutine-scope/index.html
Roman Elizarovf9e13f52017-12-21 12:23:15 +03002473[withContext]: https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines.experimental/with-context.html
Roman Elizarovd4dcbe22017-02-22 09:57:46 +03002474[NonCancellable]: https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines.experimental/-non-cancellable/index.html
2475[withTimeout]: https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines.experimental/with-timeout.html
Roman Elizarov63f6ea22017-09-06 18:42:34 +03002476[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 +03002477[async]: https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines.experimental/async.html
2478[Deferred]: https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines.experimental/-deferred/index.html
Roman Elizarovecda27f2017-04-06 23:06:26 +03002479[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 +03002480[Deferred.await]: https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines.experimental/-deferred/await.html
2481[Job.start]: https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines.experimental/-job/start.html
Roman Elizarov419a6c82017-02-09 18:36:22 +03002482[CoroutineDispatcher]: https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines.experimental/-coroutine-dispatcher/index.html
Roman Elizarovd9ae2bc2017-10-20 17:36:56 +08002483[DefaultDispatcher]: https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines.experimental/-default-dispatcher.html
Roman Elizarov66f018c2017-09-29 21:39:03 +03002484[CommonPool]: https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines.experimental/-common-pool/index.html
Roman Elizarov419a6c82017-02-09 18:36:22 +03002485[Unconfined]: https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines.experimental/-unconfined/index.html
Roman Elizarovd9ae2bc2017-10-20 17:36:56 +08002486[newSingleThreadContext]: https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines.experimental/new-single-thread-context.html
2487[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 +03002488[newCoroutineContext]: https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines.experimental/new-coroutine-context.html
Roman Elizarovd4dcbe22017-02-22 09:57:46 +03002489[CoroutineName]: https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines.experimental/-coroutine-name/index.html
Roman Elizarov88396732017-09-27 21:30:47 +03002490[Job()]: https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines.experimental/-job.html
Roman Elizarov3e387b82017-12-04 13:49:11 +03002491[kotlin.coroutines.experimental.CoroutineContext.cancelChildren]: https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines.experimental/kotlin.coroutines.experimental.-coroutine-context/cancel-children.html
Roman Elizarove82dee72017-08-18 16:49:09 +03002492[CompletableDeferred]: https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines.experimental/-completable-deferred/index.html
Roman Elizarov8a5564d2017-09-06 18:48:22 +03002493[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 +03002494<!--- INDEX kotlinx.coroutines.experimental.sync -->
Roman Elizarove82dee72017-08-18 16:49:09 +03002495[Mutex]: https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines.experimental.sync/-mutex/index.html
Roman Elizarovbff3f372017-03-01 18:12:27 +03002496[Mutex.lock]: https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines.experimental.sync/-mutex/lock.html
2497[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 +03002498[withLock]: https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines.experimental.sync/with-lock.html
Roman Elizarove0c817d2017-02-10 10:22:01 +03002499<!--- INDEX kotlinx.coroutines.experimental.channels -->
Roman Elizarove82dee72017-08-18 16:49:09 +03002500[Channel]: https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines.experimental.channels/-channel/index.html
Roman Elizarovbff3f372017-03-01 18:12:27 +03002501[SendChannel.send]: https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines.experimental.channels/-send-channel/send.html
2502[ReceiveChannel.receive]: https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines.experimental.channels/-receive-channel/receive.html
2503[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 +03002504[produce]: https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines.experimental.channels/produce.html
Roman Elizarov86349be2017-03-17 16:47:37 +03002505[consumeEach]: https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines.experimental.channels/consume-each.html
Roman Elizarov88396732017-09-27 21:30:47 +03002506[Channel()]: https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines.experimental.channels/-channel.html
Vsevolod Tolstopyatov03d2ff72018-05-29 17:28:20 +03002507[ticker]: https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines.experimental.channels/ticker.html
Vsevolod Tolstopyatov1dbc25e2018-04-18 14:50:26 +03002508[ReceiveChannel.cancel]: https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines.experimental.channels/-receive-channel/cancel.html
Vsevolod Tolstopyatov1dbc25e2018-04-18 14:50:26 +03002509[actor]: https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines.experimental.channels/actor.html
Roman Elizarovb5328a72018-06-06 18:31:21 +03002510[ReceiveChannel.onReceive]: https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines.experimental.channels/-receive-channel/on-receive.html
Roman Elizarov8a5564d2017-09-06 18:48:22 +03002511[ReceiveChannel.onReceiveOrNull]: https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines.experimental.channels/-receive-channel/on-receive-or-null.html
2512[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 +03002513<!--- INDEX kotlinx.coroutines.experimental.selects -->
2514[select]: https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines.experimental.selects/select.html
Roman Elizarov419a6c82017-02-09 18:36:22 +03002515<!--- END -->