blob: 0dedc44f078646b0048db5858c16fbee7adac3c0 [file] [log] [blame] [view]
Roman Elizarova5e653f2017-02-13 13:49:55 +03001<!--- INCLUDE .*/example-([a-z]+)-([0-9]+)\.kt
2/*
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 Elizarova5e653f2017-02-13 13:49:55 +030023<!--- KNIT kotlinx-coroutines-core/src/test/kotlin/guide/.*\.kt -->
Roman Elizarovf16fd272017-02-07 11:26:00 +030024
Roman Elizarov7deefb82017-01-31 10:33:17 +030025# Guide to kotlinx.coroutines by example
26
27This is a short guide on core features of `kotlinx.coroutines` with a series of examples.
28
Roman Elizarov1293ccd2017-02-01 18:49:54 +030029## Table of contents
30
Roman Elizarovfa7723e2017-02-06 11:17:51 +030031<!--- TOC -->
32
Roman Elizarov1293ccd2017-02-01 18:49:54 +030033* [Coroutine basics](#coroutine-basics)
34 * [Your first coroutine](#your-first-coroutine)
35 * [Bridging blocking and non-blocking worlds](#bridging-blocking-and-non-blocking-worlds)
36 * [Waiting for a job](#waiting-for-a-job)
37 * [Extract function refactoring](#extract-function-refactoring)
38 * [Coroutines ARE light-weight](#coroutines-are-light-weight)
39 * [Coroutines are like daemon threads](#coroutines-are-like-daemon-threads)
40* [Cancellation and timeouts](#cancellation-and-timeouts)
41 * [Cancelling coroutine execution](#cancelling-coroutine-execution)
42 * [Cancellation is cooperative](#cancellation-is-cooperative)
43 * [Making computation code cancellable](#making-computation-code-cancellable)
44 * [Closing resources with finally](#closing-resources-with-finally)
45 * [Run non-cancellable block](#run-non-cancellable-block)
46 * [Timeout](#timeout)
47* [Composing suspending functions](#composing-suspending-functions)
48 * [Sequential by default](#sequential-by-default)
Roman Elizarov32d95322017-02-09 15:57:31 +030049 * [Concurrent using async](#concurrent-using-async)
50 * [Lazily started async](#lazily-started-async)
51 * [Async-style functions](#async-style-functions)
Roman Elizarov2f6d7c92017-02-03 15:16:07 +030052* [Coroutine context and dispatchers](#coroutine-context-and-dispatchers)
Roman Elizarovfa7723e2017-02-06 11:17:51 +030053 * [Dispatchers and threads](#dispatchers-and-threads)
Roman Elizarov2f6d7c92017-02-03 15:16:07 +030054 * [Unconfined vs confined dispatcher](#unconfined-vs-confined-dispatcher)
55 * [Debugging coroutines and threads](#debugging-coroutines-and-threads)
56 * [Jumping between threads](#jumping-between-threads)
57 * [Job in the context](#job-in-the-context)
58 * [Children of a coroutine](#children-of-a-coroutine)
59 * [Combining contexts](#combining-contexts)
60 * [Naming coroutines for debugging](#naming-coroutines-for-debugging)
Roman Elizarov2fd7cb32017-02-11 23:18:59 +030061 * [Cancellation via explicit job](#cancellation-via-explicit-job)
Roman Elizarovb7721cf2017-02-03 19:23:08 +030062* [Channels](#channels)
63 * [Channel basics](#channel-basics)
64 * [Closing and iteration over channels](#closing-and-iteration-over-channels)
65 * [Building channel producers](#building-channel-producers)
66 * [Pipelines](#pipelines)
67 * [Prime numbers with pipeline](#prime-numbers-with-pipeline)
68 * [Fan-out](#fan-out)
69 * [Fan-in](#fan-in)
70 * [Buffered channels](#buffered-channels)
Roman Elizarovfa7723e2017-02-06 11:17:51 +030071
Roman Elizarova5e653f2017-02-13 13:49:55 +030072<!--- END_TOC -->
Roman Elizarov1293ccd2017-02-01 18:49:54 +030073
74## Coroutine basics
75
76This section covers basic coroutine concepts.
77
78### Your first coroutine
Roman Elizarov7deefb82017-01-31 10:33:17 +030079
80Run the following code:
81
82```kotlin
83fun main(args: Array<String>) {
84 launch(CommonPool) { // create new coroutine in common thread pool
85 delay(1000L) // non-blocking delay for 1 second (default time unit is ms)
86 println("World!") // print after delay
87 }
88 println("Hello,") // main function continues while coroutine is delayed
89 Thread.sleep(2000L) // block main thread for 2 seconds to keep JVM alive
90}
91```
92
Roman Elizarovfa7723e2017-02-06 11:17:51 +030093> You can get full code [here](kotlinx-coroutines-core/src/test/kotlin/guide/example-basic-01.kt)
Roman Elizarov7deefb82017-01-31 10:33:17 +030094
95Run this code:
96
97```
98Hello,
99World!
100```
101
Roman Elizarov419a6c82017-02-09 18:36:22 +0300102Essentially, coroutines are light-weight threads.
103They are launched with [launch] _coroutine builder_.
104You can achieve the same result replacing
Roman Elizarov7deefb82017-01-31 10:33:17 +0300105`launch(CommonPool) { ... }` with `thread { ... }` and `delay(...)` with `Thread.sleep(...)`. Try it.
106
107If you start by replacing `launch(CommonPool)` by `thread`, the compiler produces the following error:
108
109```
110Error: Kotlin: Suspend functions are only allowed to be called from a coroutine or another suspend function
111```
112
Roman Elizarov419a6c82017-02-09 18:36:22 +0300113That is because [delay] is a special _suspending function_ that does not block a thread, but _suspends_
Roman Elizarov7deefb82017-01-31 10:33:17 +0300114coroutine and it can be only used from a coroutine.
115
Roman Elizarov1293ccd2017-02-01 18:49:54 +0300116### Bridging blocking and non-blocking worlds
Roman Elizarov7deefb82017-01-31 10:33:17 +0300117
118The first example mixes _non-blocking_ `delay(...)` and _blocking_ `Thread.sleep(...)` in the same
119code of `main` function. It is easy to get lost. Let's cleanly separate blocking and non-blocking
Roman Elizarov419a6c82017-02-09 18:36:22 +0300120worlds by using [runBlocking]:
Roman Elizarov7deefb82017-01-31 10:33:17 +0300121
122```kotlin
123fun main(args: Array<String>) = runBlocking<Unit> { // start main coroutine
124 launch(CommonPool) { // create new coroutine in common thread pool
125 delay(1000L)
126 println("World!")
127 }
128 println("Hello,") // main coroutine continues while child is delayed
129 delay(2000L) // non-blocking delay for 2 seconds to keep JVM alive
130}
131```
132
Roman Elizarovfa7723e2017-02-06 11:17:51 +0300133> You can get full code [here](kotlinx-coroutines-core/src/test/kotlin/guide/example-basic-02.kt)
Roman Elizarov7deefb82017-01-31 10:33:17 +0300134
Roman Elizarov419a6c82017-02-09 18:36:22 +0300135The result is the same, but this code uses only non-blocking [delay].
Roman Elizarov7deefb82017-01-31 10:33:17 +0300136
137`runBlocking { ... }` works as an adaptor that is used here to start the top-level main coroutine.
138The regular code outside of `runBlocking` _blocks_, until the coroutine inside `runBlocking` is active.
139
140This is also a way to write unit-tests for suspending functions:
141
142```kotlin
143class MyTest {
144 @Test
145 fun testMySuspendingFunction() = runBlocking<Unit> {
146 // here we can use suspending functions using any assertion style that we like
147 }
148}
149```
Roman Elizarovb3d55a52017-02-03 12:47:21 +0300150
151<!--- CLEAR -->
Roman Elizarov7deefb82017-01-31 10:33:17 +0300152
Roman Elizarov1293ccd2017-02-01 18:49:54 +0300153### Waiting for a job
Roman Elizarov7deefb82017-01-31 10:33:17 +0300154
Roman Elizarov1293ccd2017-02-01 18:49:54 +0300155Delaying for a time while another coroutine is working is not a good approach. Let's explicitly
Roman Elizarov419a6c82017-02-09 18:36:22 +0300156wait (in a non-blocking way) until the background [Job] that we have launched is complete:
Roman Elizarov7deefb82017-01-31 10:33:17 +0300157
158```kotlin
159fun main(args: Array<String>) = runBlocking<Unit> {
160 val job = launch(CommonPool) { // create new coroutine and keep a reference to its Job
161 delay(1000L)
162 println("World!")
163 }
164 println("Hello,")
165 job.join() // wait until child coroutine completes
166}
167```
168
Roman Elizarovfa7723e2017-02-06 11:17:51 +0300169> You can get full code [here](kotlinx-coroutines-core/src/test/kotlin/guide/example-basic-03.kt)
Roman Elizarov7deefb82017-01-31 10:33:17 +0300170
171Now 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 +0300172the background job in any way. Much better.
Roman Elizarov7deefb82017-01-31 10:33:17 +0300173
Roman Elizarov1293ccd2017-02-01 18:49:54 +0300174### Extract function refactoring
Roman Elizarov7deefb82017-01-31 10:33:17 +0300175
176Let's extract the block of code inside `launch(CommonPool} { ... }` into a separate function. When you
177perform "Extract function" refactoring on this code you get a new function with `suspend` modifier.
178That is your first _suspending function_. Suspending functions can be used inside coroutines
179just like regular functions, but their additional feature is that they can, in turn,
180use other suspending functions, like `delay` in this example, to _suspend_ execution of a coroutine.
181
182```kotlin
183fun main(args: Array<String>) = runBlocking<Unit> {
184 val job = launch(CommonPool) { doWorld() }
185 println("Hello,")
186 job.join()
187}
188
189// this is your first suspending function
190suspend fun doWorld() {
191 delay(1000L)
192 println("World!")
193}
194```
195
Roman Elizarovfa7723e2017-02-06 11:17:51 +0300196> You can get full code [here](kotlinx-coroutines-core/src/test/kotlin/guide/example-basic-04.kt)
Roman Elizarov7deefb82017-01-31 10:33:17 +0300197
Roman Elizarov1293ccd2017-02-01 18:49:54 +0300198### Coroutines ARE light-weight
Roman Elizarov7deefb82017-01-31 10:33:17 +0300199
200Run the following code:
201
202```kotlin
203fun main(args: Array<String>) = runBlocking<Unit> {
204 val jobs = List(100_000) { // create a lot of coroutines and list their jobs
205 launch(CommonPool) {
206 delay(1000L)
207 print(".")
208 }
209 }
210 jobs.forEach { it.join() } // wait for all jobs to complete
211}
212```
213
Roman Elizarovfa7723e2017-02-06 11:17:51 +0300214> You can get full code [here](kotlinx-coroutines-core/src/test/kotlin/guide/example-basic-05.kt)
Roman Elizarov7deefb82017-01-31 10:33:17 +0300215
216It starts 100K coroutines and, after a second, each coroutine prints a dot.
217Now, try that with threads. What would happen? (Most likely your code will produce some sort of out-of-memory error)
218
Roman Elizarov1293ccd2017-02-01 18:49:54 +0300219### Coroutines are like daemon threads
Roman Elizarov7deefb82017-01-31 10:33:17 +0300220
221The following code launches a long-running coroutine that prints "I'm sleeping" twice a second and then
Roman Elizarov1293ccd2017-02-01 18:49:54 +0300222returns from the main function after some delay:
Roman Elizarov7deefb82017-01-31 10:33:17 +0300223
224```kotlin
225fun main(args: Array<String>) = runBlocking<Unit> {
226 launch(CommonPool) {
227 repeat(1000) { i ->
228 println("I'm sleeping $i ...")
229 delay(500L)
230 }
231 }
232 delay(1300L) // just quit after delay
233}
234```
235
Roman Elizarovfa7723e2017-02-06 11:17:51 +0300236> You can get full code [here](kotlinx-coroutines-core/src/test/kotlin/guide/example-basic-06.kt)
Roman Elizarov7deefb82017-01-31 10:33:17 +0300237
238You can run and see that it prints three lines and terminates:
239
240```
241I'm sleeping 0 ...
242I'm sleeping 1 ...
243I'm sleeping 2 ...
244```
245
246Active coroutines do not keep the process alive. They are like daemon threads.
247
Roman Elizarov1293ccd2017-02-01 18:49:54 +0300248## Cancellation and timeouts
249
250This section covers coroutine cancellation and timeouts.
251
252### Cancelling coroutine execution
Roman Elizarov7deefb82017-01-31 10:33:17 +0300253
254In small application the return from "main" method might sound like a good idea to get all coroutines
255implicitly terminated. In a larger, long-running application, you need finer-grained control.
Roman Elizarov419a6c82017-02-09 18:36:22 +0300256The [launch] function returns a [Job] that can be used to cancel running coroutine:
Roman Elizarov7deefb82017-01-31 10:33:17 +0300257
258```kotlin
259fun main(args: Array<String>) = runBlocking<Unit> {
260 val job = launch(CommonPool) {
261 repeat(1000) { i ->
262 println("I'm sleeping $i ...")
263 delay(500L)
264 }
265 }
266 delay(1300L) // delay a bit
Roman Elizarov1293ccd2017-02-01 18:49:54 +0300267 println("main: I'm tired of waiting!")
Roman Elizarov7deefb82017-01-31 10:33:17 +0300268 job.cancel() // cancels the job
269 delay(1300L) // delay a bit to ensure it was cancelled indeed
Roman Elizarov1293ccd2017-02-01 18:49:54 +0300270 println("main: Now I can quit.")
Roman Elizarov7deefb82017-01-31 10:33:17 +0300271}
272```
273
Roman Elizarovfa7723e2017-02-06 11:17:51 +0300274> You can get full code [here](kotlinx-coroutines-core/src/test/kotlin/guide/example-cancel-01.kt)
Roman Elizarov7deefb82017-01-31 10:33:17 +0300275
Roman Elizarov1293ccd2017-02-01 18:49:54 +0300276It produces the following output:
277
278```
279I'm sleeping 0 ...
280I'm sleeping 1 ...
281I'm sleeping 2 ...
282main: I'm tired of waiting!
283main: Now I can quit.
284```
285
286As soon as main invokes `job.cancel`, we don't see any output from the other coroutine because it was cancelled.
287
288### Cancellation is cooperative
Roman Elizarov7deefb82017-01-31 10:33:17 +0300289
Tair Rzayevaf734622017-02-01 22:30:16 +0200290Coroutine cancellation is _cooperative_. A coroutine code has to cooperate to be cancellable.
Roman Elizarov7deefb82017-01-31 10:33:17 +0300291All the suspending functions in `kotlinx.coroutines` are _cancellable_. They check for cancellation of
Roman Elizarov419a6c82017-02-09 18:36:22 +0300292coroutine and throw [CancellationException] when cancelled. However, if a coroutine is working in
Roman Elizarov7deefb82017-01-31 10:33:17 +0300293a computation and does not check for cancellation, then it cannot be cancelled, like the following
294example shows:
295
296```kotlin
297fun main(args: Array<String>) = runBlocking<Unit> {
298 val job = launch(CommonPool) {
299 var nextPrintTime = 0L
300 var i = 0
301 while (true) { // computation loop
302 val currentTime = System.currentTimeMillis()
303 if (currentTime >= nextPrintTime) {
304 println("I'm sleeping ${i++} ...")
305 nextPrintTime = currentTime + 500L
306 }
307 }
308 }
309 delay(1300L) // delay a bit
Roman Elizarov1293ccd2017-02-01 18:49:54 +0300310 println("main: I'm tired of waiting!")
Roman Elizarov7deefb82017-01-31 10:33:17 +0300311 job.cancel() // cancels the job
312 delay(1300L) // delay a bit to see if it was cancelled....
Roman Elizarov1293ccd2017-02-01 18:49:54 +0300313 println("main: Now I can quit.")
Roman Elizarov7deefb82017-01-31 10:33:17 +0300314}
315```
316
Roman Elizarovfa7723e2017-02-06 11:17:51 +0300317> You can get full code [here](kotlinx-coroutines-core/src/test/kotlin/guide/example-cancel-02.kt)
Roman Elizarov7deefb82017-01-31 10:33:17 +0300318
319Run it to see that it continues to print "I'm sleeping" even after cancellation.
320
Roman Elizarov1293ccd2017-02-01 18:49:54 +0300321### Making computation code cancellable
Roman Elizarov7deefb82017-01-31 10:33:17 +0300322
323There are two approaches to making computation code cancellable. The first one is to periodically
Roman Elizarov419a6c82017-02-09 18:36:22 +0300324invoke a suspending function. There is a [yield] function that is a good choice for that purpose.
Roman Elizarov1293ccd2017-02-01 18:49:54 +0300325The other one is to explicitly check the cancellation status. Let us try the later approach.
Roman Elizarov7deefb82017-01-31 10:33:17 +0300326
327Replace `while (true)` in the previous example with `while (isActive)` and rerun it.
328
Roman Elizarovb3d55a52017-02-03 12:47:21 +0300329```kotlin
330fun main(args: Array<String>) = runBlocking<Unit> {
331 val job = launch(CommonPool) {
332 var nextPrintTime = 0L
333 var i = 0
334 while (isActive) { // cancellable computation loop
335 val currentTime = System.currentTimeMillis()
336 if (currentTime >= nextPrintTime) {
337 println("I'm sleeping ${i++} ...")
338 nextPrintTime = currentTime + 500L
339 }
340 }
341 }
342 delay(1300L) // delay a bit
343 println("main: I'm tired of waiting!")
344 job.cancel() // cancels the job
345 delay(1300L) // delay a bit to see if it was cancelled....
346 println("main: Now I can quit.")
347}
348```
349
Roman Elizarovfa7723e2017-02-06 11:17:51 +0300350> You can get full code [here](kotlinx-coroutines-core/src/test/kotlin/guide/example-cancel-03.kt)
Roman Elizarov7deefb82017-01-31 10:33:17 +0300351
Roman Elizarov419a6c82017-02-09 18:36:22 +0300352As you can see, now this loop can be cancelled. [isActive][CoroutineScope.isActive] is a property that is available inside
353the code of coroutines via [CoroutineScope] object.
Roman Elizarov7deefb82017-01-31 10:33:17 +0300354
Roman Elizarov1293ccd2017-02-01 18:49:54 +0300355### Closing resources with finally
356
Roman Elizarov419a6c82017-02-09 18:36:22 +0300357Cancellable suspending functions throw [CancellationException] on cancellation which can be handled in
Roman Elizarov1293ccd2017-02-01 18:49:54 +0300358all the usual way. For example, the `try {...} finally {...}` and Kotlin `use` function execute their
359finalization actions normally when coroutine is cancelled:
360
361```kotlin
362fun main(args: Array<String>) = runBlocking<Unit> {
363 val job = launch(CommonPool) {
364 try {
365 repeat(1000) { i ->
366 println("I'm sleeping $i ...")
367 delay(500L)
368 }
369 } finally {
370 println("I'm running finally")
371 }
372 }
373 delay(1300L) // delay a bit
374 println("main: I'm tired of waiting!")
375 job.cancel() // cancels the job
376 delay(1300L) // delay a bit to ensure it was cancelled indeed
377 println("main: Now I can quit.")
378}
379```
380
Roman Elizarovfa7723e2017-02-06 11:17:51 +0300381> You can get full code [here](kotlinx-coroutines-core/src/test/kotlin/guide/example-cancel-04.kt)
Roman Elizarov1293ccd2017-02-01 18:49:54 +0300382
383The example above produces the following output:
384
385```
386I'm sleeping 0 ...
387I'm sleeping 1 ...
388I'm sleeping 2 ...
389main: I'm tired of waiting!
390I'm running finally
391main: Now I can quit.
392```
393
394### Run non-cancellable block
395
396Any attempt to use a suspending function in the `finally` block of the previous example will cause
Roman Elizarov419a6c82017-02-09 18:36:22 +0300397[CancellationException], because the coroutine running this code is cancelled. Usually, this is not a
Roman Elizarov1293ccd2017-02-01 18:49:54 +0300398problem, since all well-behaving closing operations (closing a file, cancelling a job, or closing any kind of a
399communication channel) are usually non-blocking and do not involve any suspending functions. However, in the
400rare case when you need to suspend in the cancelled coroutine you can wrap the corresponding code in
Roman Elizarov419a6c82017-02-09 18:36:22 +0300401`run(NonCancellable) {...}` using [run] function and [NonCancellable] context as the following example shows:
Roman Elizarov1293ccd2017-02-01 18:49:54 +0300402
403```kotlin
404fun main(args: Array<String>) = runBlocking<Unit> {
405 val job = launch(CommonPool) {
406 try {
407 repeat(1000) { i ->
408 println("I'm sleeping $i ...")
409 delay(500L)
410 }
411 } finally {
412 run(NonCancellable) {
413 println("I'm running finally")
414 delay(1000L)
415 println("And I've just delayed for 1 sec because I'm non-cancellable")
416 }
417 }
418 }
419 delay(1300L) // delay a bit
420 println("main: I'm tired of waiting!")
421 job.cancel() // cancels the job
422 delay(1300L) // delay a bit to ensure it was cancelled indeed
423 println("main: Now I can quit.")
424}
425```
426
Roman Elizarovfa7723e2017-02-06 11:17:51 +0300427> You can get full code [here](kotlinx-coroutines-core/src/test/kotlin/guide/example-cancel-05.kt)
Roman Elizarov1293ccd2017-02-01 18:49:54 +0300428
429### Timeout
430
431The most obvious reason to cancel coroutine execution in practice,
432is because its execution time has exceeded some timeout.
Roman Elizarov419a6c82017-02-09 18:36:22 +0300433While you can manually track the reference to the corresponding [Job] and launch a separate coroutine to cancel
434the tracked one after delay, there is a ready to use [withTimeout] function that does it.
Roman Elizarov1293ccd2017-02-01 18:49:54 +0300435Look at the following example:
436
437```kotlin
438fun main(args: Array<String>) = runBlocking<Unit> {
439 withTimeout(1300L) {
440 repeat(1000) { i ->
441 println("I'm sleeping $i ...")
442 delay(500L)
443 }
444 }
445}
446```
447
Roman Elizarovfa7723e2017-02-06 11:17:51 +0300448> You can get full code [here](kotlinx-coroutines-core/src/test/kotlin/guide/example-cancel-06.kt)
Roman Elizarov1293ccd2017-02-01 18:49:54 +0300449
450It produces the following output:
451
452```
453I'm sleeping 0 ...
454I'm sleeping 1 ...
455I'm sleeping 2 ...
456Exception in thread "main" java.util.concurrent.CancellationException: Timed out waiting for 1300 MILLISECONDS
457```
458
Roman Elizarov419a6c82017-02-09 18:36:22 +0300459We have not seen the [CancellationException] stack trace printed on the console before. That is because
Roman Elizarov1293ccd2017-02-01 18:49:54 +0300460inside a cancelled coroutine `CancellationException` is a considered a normal reason for coroutine completion.
461However, in this example we have used `withTimeout` right inside the `main` function.
462
463Because cancellation is just an exception, all the resources will be closed in a usual way.
464You can wrap the code with timeout in `try {...} catch (e: CancellationException) {...}` block if
465you need to do some additional action specifically on timeout.
466
467## Composing suspending functions
468
469This section covers various approaches to composition of suspending functions.
470
471### Sequential by default
472
473Assume that we have two suspending functions defined elsewhere that do something useful like some kind of
Roman Elizarovb7721cf2017-02-03 19:23:08 +0300474remote service call or computation. We just pretend they are useful, but actually each one just
475delays for a second for the purpose of this example:
Roman Elizarov1293ccd2017-02-01 18:49:54 +0300476
Roman Elizarovfa7723e2017-02-06 11:17:51 +0300477<!--- INCLUDE .*/example-compose-([0-9]+).kt
478import kotlin.system.measureTimeMillis
479-->
480
Roman Elizarov1293ccd2017-02-01 18:49:54 +0300481```kotlin
482suspend fun doSomethingUsefulOne(): Int {
483 delay(1000L) // pretend we are doing something useful here
484 return 13
485}
486
487suspend fun doSomethingUsefulTwo(): Int {
488 delay(1000L) // pretend we are doing something useful here, too
489 return 29
490}
491```
492
Roman Elizarovfa7723e2017-02-06 11:17:51 +0300493<!--- INCLUDE .*/example-compose-([0-9]+).kt -->
494
Roman Elizarov1293ccd2017-02-01 18:49:54 +0300495What do we do if need to invoke them _sequentially_ -- first `doSomethingUsefulOne` _and then_
496`doSomethingUsefulTwo` and compute the sum of their results?
497In practise we do this if we use the results of the first function to make a decision on whether we need
498to invoke the second one or to decide on how to invoke it.
499
500We just use a normal sequential invocation, because the code in the coroutine, just like in the regular
Roman Elizarov32d95322017-02-09 15:57:31 +0300501code, is _sequential_ by default. The following example demonstrates it by measuring the total
Roman Elizarov1293ccd2017-02-01 18:49:54 +0300502time it takes to execute both suspending functions:
503
504```kotlin
505fun main(args: Array<String>) = runBlocking<Unit> {
506 val time = measureTimeMillis {
507 val one = doSomethingUsefulOne()
508 val two = doSomethingUsefulTwo()
509 println("The answer is ${one + two}")
510 }
511 println("Completed in $time ms")
512}
513```
514
Roman Elizarovfa7723e2017-02-06 11:17:51 +0300515> You can get full code [here](kotlinx-coroutines-core/src/test/kotlin/guide/example-compose-01.kt)
Roman Elizarov1293ccd2017-02-01 18:49:54 +0300516
517It produces something like this:
518
519```
520The answer is 42
521Completed in 2017 ms
522```
523
Roman Elizarov32d95322017-02-09 15:57:31 +0300524### Concurrent using async
Roman Elizarov1293ccd2017-02-01 18:49:54 +0300525
526What if there are no dependencies between invocation of `doSomethingUsefulOne` and `doSomethingUsefulTwo` and
Roman Elizarov419a6c82017-02-09 18:36:22 +0300527we want to get the answer faster, by doing both _concurrently_? This is where [async] comes to help.
Roman Elizarov1293ccd2017-02-01 18:49:54 +0300528
Roman Elizarov419a6c82017-02-09 18:36:22 +0300529Conceptually, [async] is just like [launch]. It starts a separate coroutine which is a light-weight thread
530that works concurrently with all the other coroutines. The difference is that `launch` returns a [Job] and
531does not carry any resulting value, while `async` returns a [Deferred] -- a light-weight non-blocking future
Roman Elizarov32d95322017-02-09 15:57:31 +0300532that 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 +0300533but `Deferred` is also a `Job`, so you can cancel it if needed.
534
535```kotlin
536fun main(args: Array<String>) = runBlocking<Unit> {
537 val time = measureTimeMillis {
Roman Elizarov32d95322017-02-09 15:57:31 +0300538 val one = async(CommonPool) { doSomethingUsefulOne() }
539 val two = async(CommonPool) { doSomethingUsefulTwo() }
Roman Elizarov1293ccd2017-02-01 18:49:54 +0300540 println("The answer is ${one.await() + two.await()}")
541 }
542 println("Completed in $time ms")
543}
544```
545
Roman Elizarovfa7723e2017-02-06 11:17:51 +0300546> You can get full code [here](kotlinx-coroutines-core/src/test/kotlin/guide/example-compose-02.kt)
Roman Elizarov1293ccd2017-02-01 18:49:54 +0300547
548It produces something like this:
549
550```
551The answer is 42
552Completed in 1017 ms
553```
554
555This is twice as fast, because we have concurrent execution of two coroutines.
556Note, that concurrency with coroutines is always explicit.
557
Roman Elizarov32d95322017-02-09 15:57:31 +0300558### Lazily started async
Roman Elizarov1293ccd2017-02-01 18:49:54 +0300559
Roman Elizarov419a6c82017-02-09 18:36:22 +0300560There is a laziness option to [async] with `start = false` parameter.
561It starts coroutine only when its result is needed by some
562[await][Deferred.await] or if a [start][Job.start] function
Roman Elizarov32d95322017-02-09 15:57:31 +0300563is invoked. Run the following example that differs from the previous one only by this option:
Roman Elizarov1293ccd2017-02-01 18:49:54 +0300564
565```kotlin
566fun main(args: Array<String>) = runBlocking<Unit> {
567 val time = measureTimeMillis {
Roman Elizarov32d95322017-02-09 15:57:31 +0300568 val one = async(CommonPool, start = false) { doSomethingUsefulOne() }
569 val two = async(CommonPool, start = false) { doSomethingUsefulTwo() }
Roman Elizarov1293ccd2017-02-01 18:49:54 +0300570 println("The answer is ${one.await() + two.await()}")
571 }
572 println("Completed in $time ms")
573}
574```
575
Roman Elizarovfa7723e2017-02-06 11:17:51 +0300576> You can get full code [here](kotlinx-coroutines-core/src/test/kotlin/guide/example-compose-03.kt)
Roman Elizarov1293ccd2017-02-01 18:49:54 +0300577
578It produces something like this:
579
580```
581The answer is 42
582Completed in 2017 ms
583```
584
Roman Elizarov32d95322017-02-09 15:57:31 +0300585So, we are back to sequential execution, because we _first_ start and await for `one`, _and then_ start and await
586for `two`. It is not the intended use-case for laziness. It is designed as a replacement for
587the standard `lazy` function in cases when computation of the value involves suspending functions.
588
589### Async-style functions
590
591We can define async-style functions that invoke `doSomethingUsefulOne` and `doSomethingUsefulTwo`
Roman Elizarov419a6c82017-02-09 18:36:22 +0300592_asynchronously_ using [async] coroutine builder. It is a good style to name such functions with
Roman Elizarov32d95322017-02-09 15:57:31 +0300593either "async" prefix of "Async" suffix to highlight the fact that they only start asynchronous
594computation and one needs to use the resulting deferred value to get the result.
595
596```kotlin
597// The result type of asyncSomethingUsefulOne is Deferred<Int>
598fun asyncSomethingUsefulOne() = async(CommonPool) {
599 doSomethingUsefulOne()
600}
601
602// The result type of asyncSomethingUsefulTwo is Deferred<Int>
603fun asyncSomethingUsefulTwo() = async(CommonPool) {
604 doSomethingUsefulTwo()
605}
606```
607
608Note, that these `asyncXXX` function are **not** _suspending_ functions. They can be used from anywhere.
609However, their use always implies asynchronous (here meaning _concurrent_) execution of their action
610with the invoking code.
611
612The following example shows their use outside of coroutine:
613
614```kotlin
615// note, that we don't have `runBlocking` to the right of `main` in this example
616fun main(args: Array<String>) {
617 val time = measureTimeMillis {
618 // we can initiate async actions outside of a coroutine
619 val one = asyncSomethingUsefulOne()
620 val two = asyncSomethingUsefulTwo()
621 // but waiting for a result must involve either suspending or blocking.
622 // here we use `runBlocking { ... }` to block the main thread while waiting for the result
623 runBlocking {
624 println("The answer is ${one.await() + two.await()}")
625 }
626 }
627 println("Completed in $time ms")
628}
629```
630
631> You can get full code [here](kotlinx-coroutines-core/src/test/kotlin/guide/example-compose-04.kt)
Roman Elizarov1293ccd2017-02-01 18:49:54 +0300632
Roman Elizarov2f6d7c92017-02-03 15:16:07 +0300633## Coroutine context and dispatchers
634
Roman Elizarov32d95322017-02-09 15:57:31 +0300635We've already seen `launch(CommonPool) {...}`, `async(CommonPool) {...}`, `run(NonCancellable) {...}`, etc.
Roman Elizarov419a6c82017-02-09 18:36:22 +0300636In these code snippets [CommonPool] and [NonCancellable] are _coroutine contexts_.
Roman Elizarov2f6d7c92017-02-03 15:16:07 +0300637This section covers other available choices.
638
639### Dispatchers and threads
640
Roman Elizarov419a6c82017-02-09 18:36:22 +0300641Coroutine context includes a [_coroutine dispatcher_][CoroutineDispatcher] which determines what thread or threads
Roman Elizarov2f6d7c92017-02-03 15:16:07 +0300642the corresponding coroutine uses for its execution. Coroutine dispatcher can confine coroutine execution
643to a specific thread, dispatch it to a thread pool, or let it run unconfined. Try the following example:
644
645```kotlin
646fun main(args: Array<String>) = runBlocking<Unit> {
647 val jobs = arrayListOf<Job>()
648 jobs += launch(Unconfined) { // not confined -- will work with main thread
649 println(" 'Unconfined': I'm working in thread ${Thread.currentThread().name}")
650 }
651 jobs += launch(context) { // context of the parent, runBlocking coroutine
652 println(" 'context': I'm working in thread ${Thread.currentThread().name}")
653 }
654 jobs += launch(CommonPool) { // will get dispatched to ForkJoinPool.commonPool (or equivalent)
655 println(" 'CommonPool': I'm working in thread ${Thread.currentThread().name}")
656 }
657 jobs += launch(newSingleThreadContext("MyOwnThread")) { // will get its own new thread
658 println(" 'newSTC': I'm working in thread ${Thread.currentThread().name}")
659 }
660 jobs.forEach { it.join() }
661}
662```
663
Roman Elizarovfa7723e2017-02-06 11:17:51 +0300664> You can get full code [here](kotlinx-coroutines-core/src/test/kotlin/guide/example-context-01.kt)
Roman Elizarov2f6d7c92017-02-03 15:16:07 +0300665
666It produces the following output (maybe in different order):
667
668```
669 'Unconfined': I'm working in thread main
670 'CommonPool': I'm working in thread ForkJoinPool.commonPool-worker-1
671 'newSTC': I'm working in thread MyOwnThread
672 'context': I'm working in thread main
673```
674
Roman Elizarov419a6c82017-02-09 18:36:22 +0300675The difference between parent [context][CoroutineScope.context] and [Unconfined] context will be shown later.
Roman Elizarov2f6d7c92017-02-03 15:16:07 +0300676
677### Unconfined vs confined dispatcher
678
Roman Elizarov419a6c82017-02-09 18:36:22 +0300679The [Unconfined] coroutine dispatcher starts coroutine in the caller thread, but only until the
Roman Elizarov2f6d7c92017-02-03 15:16:07 +0300680first suspension point. After suspension it resumes in the thread that is fully determined by the
681suspending function that was invoked. Unconfined dispatcher is appropriate when coroutine does not
682consume CPU time nor updates any shared data (like UI) that is confined to a specific thread.
683
Roman Elizarov419a6c82017-02-09 18:36:22 +0300684On the other side, [context][CoroutineScope.context] property that is available inside the block of any coroutine
685via [CoroutineScope] interface, is a reference to a context of this particular coroutine.
686This way, a parent context can be inherited. The default context of [runBlocking], in particular,
Roman Elizarov2f6d7c92017-02-03 15:16:07 +0300687is confined to be invoker thread, so inheriting it has the effect of confining execution to
688this thread with a predictable FIFO scheduling.
689
690```kotlin
691fun main(args: Array<String>) = runBlocking<Unit> {
692 val jobs = arrayListOf<Job>()
693 jobs += launch(Unconfined) { // not confined -- will work with main thread
694 println(" 'Unconfined': I'm working in thread ${Thread.currentThread().name}")
695 delay(1000)
696 println(" 'Unconfined': After delay in thread ${Thread.currentThread().name}")
697 }
698 jobs += launch(context) { // context of the parent, runBlocking coroutine
699 println(" 'context': I'm working in thread ${Thread.currentThread().name}")
700 delay(1000)
701 println(" 'context': After delay in thread ${Thread.currentThread().name}")
702 }
703 jobs.forEach { it.join() }
704}
705```
706
Roman Elizarovfa7723e2017-02-06 11:17:51 +0300707> You can get full code [here](kotlinx-coroutines-core/src/test/kotlin/guide/example-contest-02.kt)
Roman Elizarov2f6d7c92017-02-03 15:16:07 +0300708
709Produces the output:
710
711```
712 'Unconfined': I'm working in thread main
713 'context': I'm working in thread main
714 'Unconfined': After delay in thread kotlinx.coroutines.ScheduledExecutor
715 'context': After delay in thread main
716```
717
718So, the coroutine the had inherited `context` of `runBlocking {...}` continues to execute in the `main` thread,
Roman Elizarov419a6c82017-02-09 18:36:22 +0300719while the unconfined one had resumed in the scheduler thread that [delay] function is using.
Roman Elizarov2f6d7c92017-02-03 15:16:07 +0300720
721### Debugging coroutines and threads
722
Roman Elizarov419a6c82017-02-09 18:36:22 +0300723Coroutines can suspend on one thread and resume on another thread with [Unconfined] dispatcher or
724with a multi-threaded dispatcher like [CommonPool]. Even with a single-threaded dispatcher it might be hard to
Roman Elizarov2f6d7c92017-02-03 15:16:07 +0300725figure out what coroutine was doing what, where, and when. The common approach to debugging applications with
726threads is to print the thread name in the log file on each log statement. This feature is universally supported
727by logging frameworks. When using coroutines, the thread name alone does not give much of a context, so
728`kotlinx.coroutines` includes debugging facilities to make it easier.
729
730Run the following code with `-Dkotlinx.coroutines.debug` JVM option:
731
732```kotlin
733fun log(msg: String) = println("[${Thread.currentThread().name}] $msg")
734
735fun main(args: Array<String>) = runBlocking<Unit> {
Roman Elizarov32d95322017-02-09 15:57:31 +0300736 val a = async(context) {
Roman Elizarov2f6d7c92017-02-03 15:16:07 +0300737 log("I'm computing a piece of the answer")
738 6
739 }
Roman Elizarov32d95322017-02-09 15:57:31 +0300740 val b = async(context) {
Roman Elizarov2f6d7c92017-02-03 15:16:07 +0300741 log("I'm computing another piece of the answer")
742 7
743 }
744 log("The answer is ${a.await() * b.await()}")
745}
746```
747
Roman Elizarovfa7723e2017-02-06 11:17:51 +0300748> You can get full code [here](kotlinx-coroutines-core/src/test/kotlin/guide/example-context-03.kt)
Roman Elizarov2f6d7c92017-02-03 15:16:07 +0300749
Roman Elizarovb7721cf2017-02-03 19:23:08 +0300750There are three coroutines. The main coroutine (#1) -- `runBlocking` one,
Roman Elizarov2f6d7c92017-02-03 15:16:07 +0300751and two coroutines computing deferred values `a` (#2) and `b` (#3).
752They are all executing in the context of `runBlocking` and are confined to the main thread.
753The output of this code is:
754
755```
756[main @coroutine#2] I'm computing a piece of the answer
757[main @coroutine#3] I'm computing another piece of the answer
758[main @coroutine#1] The answer is 42
759```
760
761The `log` function prints the name of the thread in square brackets and you can see, that it is the `main`
762thread, but the identifier of the currently executing coroutine is appended to it. This identifier
763is consecutively assigned to all created coroutines when debugging mode is turned on.
764
Roman Elizarov419a6c82017-02-09 18:36:22 +0300765You can read more about debugging facilities in the documentation for [newCoroutineContext] function.
Roman Elizarov2f6d7c92017-02-03 15:16:07 +0300766
767### Jumping between threads
768
769Run the following code with `-Dkotlinx.coroutines.debug` JVM option:
770
771```kotlin
772fun log(msg: String) = println("[${Thread.currentThread().name}] $msg")
773
774fun main(args: Array<String>) {
775 val ctx1 = newSingleThreadContext("Ctx1")
776 val ctx2 = newSingleThreadContext("Ctx2")
777 runBlocking(ctx1) {
778 log("Started in ctx1")
779 run(ctx2) {
780 log("Working in ctx2")
781 }
782 log("Back to ctx1")
783 }
784}
785```
786
Roman Elizarovfa7723e2017-02-06 11:17:51 +0300787> You can get full code [here](kotlinx-coroutines-core/src/test/kotlin/guide/example-context-04.kt)
Roman Elizarov2f6d7c92017-02-03 15:16:07 +0300788
Roman Elizarov419a6c82017-02-09 18:36:22 +0300789It demonstrates two new techniques. One is using [runBlocking] with an explicitly specified context, and
790the second one is using [run] function to change a context of a coroutine while still staying in the
Roman Elizarov2f6d7c92017-02-03 15:16:07 +0300791same coroutine as you can see in the output below:
792
793```
794[Ctx1 @coroutine#1] Started in ctx1
795[Ctx2 @coroutine#1] Working in ctx2
796[Ctx1 @coroutine#1] Back to ctx1
797```
798
799### Job in the context
800
Roman Elizarov419a6c82017-02-09 18:36:22 +0300801The coroutine [Job] is part of its context. The coroutine can retrieve it from its own context
Roman Elizarov2f6d7c92017-02-03 15:16:07 +0300802using `context[Job]` expression:
803
804```kotlin
805fun main(args: Array<String>) = runBlocking<Unit> {
806 println("My job is ${context[Job]}")
807}
808```
809
Roman Elizarovfa7723e2017-02-06 11:17:51 +0300810> You can get full code [here](kotlinx-coroutines-core/src/test/kotlin/guide/example-context-05.kt)
Roman Elizarov2f6d7c92017-02-03 15:16:07 +0300811
812It produces
813
814```
815My job is BlockingCoroutine{isActive=true}
816```
817
Roman Elizarov419a6c82017-02-09 18:36:22 +0300818So, [isActive][CoroutineScope.isActive] in [CoroutineScope] is just a convenient shortcut for `context[Job]!!.isActive`.
Roman Elizarov2f6d7c92017-02-03 15:16:07 +0300819
820### Children of a coroutine
821
Roman Elizarov419a6c82017-02-09 18:36:22 +0300822When [context][CoroutineScope.context] of a coroutine is used to launch another coroutine,
823the [Job] of the new coroutine becomes
Roman Elizarov2f6d7c92017-02-03 15:16:07 +0300824a _child_ of the parent coroutine's job. When the parent coroutine is cancelled, all its children
825are recursively cancelled, too.
826
827```kotlin
828fun main(args: Array<String>) = runBlocking<Unit> {
829 // start a coroutine to process some kind of incoming request
830 val request = launch(CommonPool) {
831 // it spawns two other jobs, one with its separate context
832 val job1 = launch(CommonPool) {
833 println("job1: I have my own context and execute independently!")
834 delay(1000)
835 println("job1: I am not affected by cancellation of the request")
836 }
837 // and the other inherits the parent context
838 val job2 = launch(context) {
839 println("job2: I am a child of the request coroutine")
840 delay(1000)
841 println("job2: I will not execute this line if my parent request is cancelled")
842 }
843 // request completes when both its sub-jobs complete:
844 job1.join()
845 job2.join()
846 }
847 delay(500)
848 request.cancel() // cancel processing of the request
849 delay(1000) // delay a second to see what happens
850 println("main: Who has survived request cancellation?")
851}
852```
853
Roman Elizarovfa7723e2017-02-06 11:17:51 +0300854> You can get full code [here](kotlinx-coroutines-core/src/test/kotlin/guide/example-context-06.kt)
Roman Elizarov2f6d7c92017-02-03 15:16:07 +0300855
856The output of this code is:
857
858```
859job1: I have my own context and execute independently!
860job2: I am a child of the request coroutine
861job1: I am not affected by cancellation of the request
862main: Who has survived request cancellation?
863```
864
865### Combining contexts
866
867Coroutine context can be combined using `+` operator. The context on the right-hand side replaces relevant entries
Roman Elizarov419a6c82017-02-09 18:36:22 +0300868of 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 +0300869its dispatcher replaced:
870
871```kotlin
872fun main(args: Array<String>) = runBlocking<Unit> {
873 // start a coroutine to process some kind of incoming request
874 val request = launch(context) { // use the context of `runBlocking`
875 // spawns CPU-intensive child job in CommonPool !!!
876 val job = launch(context + CommonPool) {
877 println("job: I am a child of the request coroutine, but with a different dispatcher")
878 delay(1000)
879 println("job: I will not execute this line if my parent request is cancelled")
880 }
881 job.join() // request completes when its sub-job completes
882 }
883 delay(500)
884 request.cancel() // cancel processing of the request
885 delay(1000) // delay a second to see what happens
886 println("main: Who has survived request cancellation?")
887}
888```
889
Roman Elizarovfa7723e2017-02-06 11:17:51 +0300890> You can get full code [here](kotlinx-coroutines-core/src/test/kotlin/guide/example-context-07.kt)
Roman Elizarov2f6d7c92017-02-03 15:16:07 +0300891
892The expected outcome of this code is:
893
894```
895job: I am a child of the request coroutine, but with a different dispatcher
896main: Who has survived request cancellation?
897```
898
899### Naming coroutines for debugging
900
Roman Elizarovb7721cf2017-02-03 19:23:08 +0300901Automatically assigned ids are good when coroutines log often and you just need to correlate log records
Roman Elizarov2f6d7c92017-02-03 15:16:07 +0300902coming from the same coroutine. However, when coroutine is tied to the processing of a specific request
903or doing some specific background task, it is better to name it explicitly for debugging purposes.
Roman Elizarov419a6c82017-02-09 18:36:22 +0300904[CoroutineName] serves the same function as a thread name. It'll get displayed in the thread name that
Roman Elizarov2f6d7c92017-02-03 15:16:07 +0300905is executing this coroutine when debugging more is turned on.
906
907The following example demonstrates this concept:
908
909```kotlin
910fun log(msg: String) = println("[${Thread.currentThread().name}] $msg")
911
912fun main(args: Array<String>) = runBlocking(CoroutineName("main")) {
913 log("Started main coroutine")
914 // run two background value computations
Roman Elizarov32d95322017-02-09 15:57:31 +0300915 val v1 = async(CommonPool + CoroutineName("v1coroutine")) {
Roman Elizarov2f6d7c92017-02-03 15:16:07 +0300916 log("Computing v1")
917 delay(500)
918 252
919 }
Roman Elizarov32d95322017-02-09 15:57:31 +0300920 val v2 = async(CommonPool + CoroutineName("v2coroutine")) {
Roman Elizarov2f6d7c92017-02-03 15:16:07 +0300921 log("Computing v2")
922 delay(1000)
923 6
924 }
925 log("The answer for v1 / v2 = ${v1.await() / v2.await()}")
926}
927```
928
Roman Elizarovfa7723e2017-02-06 11:17:51 +0300929> You can get full code [here](kotlinx-coroutines-core/src/test/kotlin/guide/example-context-08.kt)
Roman Elizarov2f6d7c92017-02-03 15:16:07 +0300930
931The output it produces with `-Dkotlinx.coroutines.debug` JVM option is similar to:
932
933```
934[main @main#1] Started main coroutine
935[ForkJoinPool.commonPool-worker-1 @v1coroutine#2] Computing v1
936[ForkJoinPool.commonPool-worker-2 @v2coroutine#3] Computing v2
937[main @main#1] The answer for v1 / v2 = 42
938```
Roman Elizarov1293ccd2017-02-01 18:49:54 +0300939
Roman Elizarov2fd7cb32017-02-11 23:18:59 +0300940### Cancellation via explicit job
941
942Let us put our knowledge about contexts, children and jobs together. Assume that our application has
943an object with a lifecycle, but that object is not a coroutine. For example, we are writing an Android application
944and launch various coroutines in the context of an Android activity to perform asynchronous operations to fetch
945and update data, do animations, etc. All of these coroutines must be cancelled when activity is destroyed
946to avoid memory leaks.
947
948We can manage a lifecycle of our coroutines by creating an instance of [Job] that is tied to
949the lifecycle of our activity. A job instance is created using [Job()][Job.invoke] factory function
950as the following example shows. We need to make sure that all the coroutines are started
951with this job in their context and then a single invocation of [Job.cancel] terminates them all.
952
953```kotlin
954fun main(args: Array<String>) = runBlocking<Unit> {
955 val job = Job() // create a job object to manage our lifecycle
956 // now launch ten coroutines for a demo, each working for a different time
957 val coroutines = List(10) { i ->
958 // they are all children of our job object
959 launch(context + job) { // we use the context of main runBlocking thread, but with our own job object
960 delay(i * 200L) // variable delay 0ms, 200ms, 400ms, ... etc
961 println("Coroutine $i is done")
962 }
963 }
964 println("Launched ${coroutines.size} coroutines")
965 delay(500L) // delay for half a second
966 println("Cancelling job!")
967 job.cancel() // cancel our job.. !!!
968 delay(1000L) // delay for more to see if our coroutines are still working
969}
970```
971
972> You can get full code [here](kotlinx-coroutines-core/src/test/kotlin/guide/example-context-09.kt)
973
974The output of this example is:
975
976```
977Launched 10 coroutines
978Coroutine 0 is done
979Coroutine 1 is done
980Coroutine 2 is done
981Cancelling job!
982```
983
984As you can see, only the first three coroutines had printed a message and the others were cancelled
985by a single invocation of `job.cancel()`. So all we need to do in our hypothetical Android
986application is to create a parent job object when activity is created, use it for child coroutines,
987and cancel it when activity is destroyed.
988
Roman Elizarovb7721cf2017-02-03 19:23:08 +0300989## Channels
Roman Elizarov7deefb82017-01-31 10:33:17 +0300990
Roman Elizarovb7721cf2017-02-03 19:23:08 +0300991Deferred values provide a convenient way to transfer a single value between coroutines.
992Channels provide a way to transfer a stream of values.
993
994<!--- INCLUDE .*/example-channel-([0-9]+).kt
995import kotlinx.coroutines.experimental.channels.*
996-->
997
998### Channel basics
999
Roman Elizarov419a6c82017-02-09 18:36:22 +03001000A [Channel] is conceptually very similar to `BlockingQueue`. One key difference is that
1001instead of a blocking `put` operation it has a suspending [send][SendChannel.send], and instead of
1002a blocking `take` operation it has a suspending [receive][ReceiveChannel.receive].
Roman Elizarovb7721cf2017-02-03 19:23:08 +03001003
1004```kotlin
1005fun main(args: Array<String>) = runBlocking<Unit> {
1006 val channel = Channel<Int>()
1007 launch(CommonPool) {
1008 // this might be heavy CPU-consuming computation or async logic, we'll just send five squares
1009 for (x in 1..5) channel.send(x * x)
1010 }
1011 // here we print five received integers:
1012 repeat(5) { println(channel.receive()) }
1013 println("Done!")
1014}
1015```
1016
1017> You can get full code [here](kotlinx-coroutines-core/src/test/kotlin/guide/example-channel-01.kt)
1018
1019### Closing and iteration over channels
1020
1021Unlike a queue, a channel can be closed to indicate that no more elements are coming.
1022On the receiver side it is convenient to use a regular `for` loop to receive elements
1023from the channel.
1024
Roman Elizarov419a6c82017-02-09 18:36:22 +03001025Conceptually, a [close][SendChannel.close] is like sending a special close token to the channel.
Roman Elizarovb7721cf2017-02-03 19:23:08 +03001026The iteration stops as soon as this close token is received, so there is a guarantee
1027that all previously sent elements before the close are received:
1028
1029```kotlin
1030fun main(args: Array<String>) = runBlocking<Unit> {
1031 val channel = Channel<Int>()
1032 launch(CommonPool) {
1033 for (x in 1..5) channel.send(x * x)
1034 channel.close() // we're done sending
1035 }
1036 // here we print received values using `for` loop (until the channel is closed)
1037 for (y in channel) println(y)
1038 println("Done!")
1039}
1040```
1041
1042> You can get full code [here](kotlinx-coroutines-core/src/test/kotlin/guide/example-channel-02.kt)
1043
1044### Building channel producers
1045
Roman Elizarova5e653f2017-02-13 13:49:55 +03001046The pattern where a coroutine is producing a sequence of elements is quite common.
1047This is a part of _producer-consumer_ pattern that is often found in concurrent code.
Roman Elizarovb7721cf2017-02-03 19:23:08 +03001048You 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 +03001049to common sense that results must be returned from functions.
1050
1051There is a convenience coroutine builder named [produce] that makes it easy to do it right:
Roman Elizarovb7721cf2017-02-03 19:23:08 +03001052
1053```kotlin
Roman Elizarova5e653f2017-02-13 13:49:55 +03001054fun produceSquares() = produce<Int>(CommonPool) {
Roman Elizarovb7721cf2017-02-03 19:23:08 +03001055 for (x in 1..5) send(x * x)
1056}
1057
1058fun main(args: Array<String>) = runBlocking<Unit> {
1059 val squares = produceSquares()
1060 for (y in squares) println(y)
1061 println("Done!")
1062}
1063```
1064
1065> You can get full code [here](kotlinx-coroutines-core/src/test/kotlin/guide/example-channel-03.kt)
1066
1067### Pipelines
1068
1069Pipeline is a pattern where one coroutine is producing, possibly infinite, stream of values:
1070
1071```kotlin
Roman Elizarova5e653f2017-02-13 13:49:55 +03001072fun produceNumbers() = produce<Int>(CommonPool) {
Roman Elizarovb7721cf2017-02-03 19:23:08 +03001073 var x = 1
1074 while (true) send(x++) // infinite stream of integers starting from 1
1075}
1076```
1077
Roman Elizarova5e653f2017-02-13 13:49:55 +03001078And another coroutine or coroutines are consuming that stream, doing some processing, and producing some other results.
Roman Elizarovb7721cf2017-02-03 19:23:08 +03001079In the below example the numbers are just squared:
1080
1081```kotlin
Roman Elizarova5e653f2017-02-13 13:49:55 +03001082fun square(numbers: ReceiveChannel<Int>) = produce<Int>(CommonPool) {
Roman Elizarovb7721cf2017-02-03 19:23:08 +03001083 for (x in numbers) send(x * x)
1084}
1085```
1086
Roman Elizarova5e653f2017-02-13 13:49:55 +03001087The main code starts and connects the whole pipeline:
Roman Elizarovb7721cf2017-02-03 19:23:08 +03001088
1089```kotlin
1090fun main(args: Array<String>) = runBlocking<Unit> {
1091 val numbers = produceNumbers() // produces integers from 1 and on
1092 val squares = square(numbers) // squares integers
1093 for (i in 1..5) println(squares.receive()) // print first five
1094 println("Done!") // we are done
1095 squares.cancel() // need to cancel these coroutines in a larger app
1096 numbers.cancel()
1097}
1098```
1099
1100> You can get full code [here](kotlinx-coroutines-core/src/test/kotlin/guide/example-channel-04.kt)
1101
1102We don't have to cancel these coroutines in this example app, because
1103[coroutines are like daemon threads](#coroutines-are-like-daemon-threads),
1104but in a larger app we'll need to stop our pipeline if we don't need it anymore.
1105Alternatively, we could have run pipeline coroutines as
1106[children of a coroutine](#children-of-a-coroutine).
1107
1108### Prime numbers with pipeline
1109
Cedric Beustfa0b28f2017-02-07 07:07:25 -08001110Let's take pipelines to the extreme with an example that generates prime numbers using a pipeline
Roman Elizarovb7721cf2017-02-03 19:23:08 +03001111of coroutines. We start with an infinite sequence of numbers. This time we introduce an
1112explicit context parameter, so that caller can control where our coroutines run:
1113
1114<!--- INCLUDE kotlinx-coroutines-core/src/test/kotlin/guide/example-channel-05.kt
1115import kotlin.coroutines.experimental.CoroutineContext
1116-->
1117
1118```kotlin
Roman Elizarova5e653f2017-02-13 13:49:55 +03001119fun numbersFrom(context: CoroutineContext, start: Int) = produce<Int>(context) {
Roman Elizarovb7721cf2017-02-03 19:23:08 +03001120 var x = start
1121 while (true) send(x++) // infinite stream of integers from start
1122}
1123```
1124
1125The following pipeline stage filters an incoming stream of numbers, removing all the numbers
1126that are divisible by the given prime number:
1127
1128```kotlin
Roman Elizarova5e653f2017-02-13 13:49:55 +03001129fun filter(context: CoroutineContext, numbers: ReceiveChannel<Int>, prime: Int) = produce<Int>(context) {
Roman Elizarovb7721cf2017-02-03 19:23:08 +03001130 for (x in numbers) if (x % prime != 0) send(x)
1131}
1132```
1133
1134Now 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 +03001135and launching new pipeline stage for each prime number found:
1136
1137```
Roman Elizarova5e653f2017-02-13 13:49:55 +03001138numbersFrom(2) -> filter(2) -> filter(3) -> filter(5) -> filter(7) ...
Roman Elizarov62500ba2017-02-09 18:55:40 +03001139```
1140
1141The following example prints the first ten prime numbers,
Roman Elizarovb7721cf2017-02-03 19:23:08 +03001142running the whole pipeline in the context of the main thread:
1143
1144```kotlin
1145fun main(args: Array<String>) = runBlocking<Unit> {
1146 var cur = numbersFrom(context, 2)
1147 for (i in 1..10) {
1148 val prime = cur.receive()
1149 println(prime)
1150 cur = filter(context, cur, prime)
1151 }
1152}
1153```
1154
1155> You can get full code [here](kotlinx-coroutines-core/src/test/kotlin/guide/example-channel-05.kt)
1156
1157The output of this code is:
1158
1159```
11602
11613
11625
11637
116411
116513
116617
116719
116823
116929
1170```
1171
Roman Elizarova5e653f2017-02-13 13:49:55 +03001172Note, that you can build the same pipeline using `buildIterator` coroutine builder from the standard library.
1173Replace `produce` with `buildIterator`, `send` with `yield`, `receive` with `next`,
Roman Elizarov62500ba2017-02-09 18:55:40 +03001174`ReceiveChannel` with `Iterator`, and get rid of the context. You will not need `runBlocking` either.
1175However, the benefit of a pipeline that uses channels as shown above is that it can actually use
1176multiple CPU cores if you run it in [CommonPool] context.
1177
Roman Elizarova5e653f2017-02-13 13:49:55 +03001178Anyway, this is an extremely impractical way to find prime numbers. In practice, pipelines do involve some
Roman Elizarov62500ba2017-02-09 18:55:40 +03001179other suspending invocations (like asynchronous calls to remote services) and these pipelines cannot be
1180built using `buildSeqeunce`/`buildIterator`, because they do not allow arbitrary suspension, unlike
Roman Elizarova5e653f2017-02-13 13:49:55 +03001181`produce` which is fully asynchronous.
Roman Elizarov62500ba2017-02-09 18:55:40 +03001182
Roman Elizarovb7721cf2017-02-03 19:23:08 +03001183### Fan-out
1184
1185Multiple coroutines may receive from the same channel, distributing work between themselves.
1186Let us start with a producer coroutine that is periodically producing integers
1187(ten numbers per second):
1188
1189```kotlin
Roman Elizarova5e653f2017-02-13 13:49:55 +03001190fun produceNumbers() = produce<Int>(CommonPool) {
Roman Elizarovb7721cf2017-02-03 19:23:08 +03001191 var x = 1 // start from 1
1192 while (true) {
1193 send(x++) // produce next
1194 delay(100) // wait 0.1s
1195 }
1196}
1197```
1198
1199Then we can have several processor coroutines. In this example, they just print their id and
1200received number:
1201
1202```kotlin
1203fun launchProcessor(id: Int, channel: ReceiveChannel<Int>) = launch(CommonPool) {
1204 while (true) {
1205 val x = channel.receive()
1206 println("Processor #$id received $x")
1207 }
1208}
1209```
1210
1211Now let us launch five processors and let them work for a second. See what happens:
1212
1213```kotlin
1214fun main(args: Array<String>) = runBlocking<Unit> {
1215 val producer = produceNumbers()
1216 repeat(5) { launchProcessor(it, producer) }
1217 delay(1000)
1218 producer.cancel() // cancel producer coroutine and thus kill them all
1219}
1220```
1221
1222> You can get full code [here](kotlinx-coroutines-core/src/test/kotlin/guide/example-channel-06.kt)
1223
1224The output will be similar to the the following one, albeit the processor ids that receive
1225each specific integer may be different:
1226
1227```
1228Processor #2 received 1
1229Processor #4 received 2
1230Processor #0 received 3
1231Processor #1 received 4
1232Processor #3 received 5
1233Processor #2 received 6
1234Processor #4 received 7
1235Processor #0 received 8
1236Processor #1 received 9
1237Processor #3 received 10
1238```
1239
1240Note, that cancelling a producer coroutine closes its channel, thus eventually terminating iteration
1241over the channel that processor coroutines are doing.
1242
1243### Fan-in
1244
1245Multiple coroutines may send to the same channel.
1246For example, let us have a channel of strings, and a suspending function that
1247repeatedly sends a specified string to this channel with a specified delay:
1248
1249```kotlin
1250suspend fun sendString(channel: SendChannel<String>, s: String, time: Long) {
1251 while (true) {
1252 delay(time)
1253 channel.send(s)
1254 }
1255}
1256```
1257
Cedric Beustfa0b28f2017-02-07 07:07:25 -08001258Now, let us see what happens if we launch a couple of coroutines sending strings
Roman Elizarovb7721cf2017-02-03 19:23:08 +03001259(in this example we launch them in the context of the main thread):
1260
1261```kotlin
1262fun main(args: Array<String>) = runBlocking<Unit> {
1263 val channel = Channel<String>()
1264 launch(context) { sendString(channel, "foo", 200L) }
1265 launch(context) { sendString(channel, "BAR!", 500L) }
1266 repeat(6) { // receive first six
1267 println(channel.receive())
1268 }
1269}
1270```
1271
1272> You can get full code [here](kotlinx-coroutines-core/src/test/kotlin/guide/example-channel-07.kt)
1273
1274The output is:
1275
1276```
1277foo
1278foo
1279BAR!
1280foo
1281foo
1282BAR!
1283```
1284
1285### Buffered channels
1286
1287The channels shown so far had no buffer. Unbuffered channels transfer elements when sender and receiver
1288meet each other (aka rendezvous). If send is invoked first, then it is suspended until receive is invoked,
1289if receive is invoked first, it is suspended until send is invoked.
Roman Elizarov419a6c82017-02-09 18:36:22 +03001290
Roman Elizarova5e653f2017-02-13 13:49:55 +03001291Both [Channel()][Channel.invoke] factory function and [produce] builder take an optional `capacity` parameter to
Roman Elizarovb7721cf2017-02-03 19:23:08 +03001292specify _buffer size_. Buffer allows senders to send multiple elements before suspending,
1293similar to the `BlockingQueue` with a specified capacity, which blocks when buffer is full.
1294
1295Take a look at the behavior of the following code:
1296
1297```kotlin
1298fun main(args: Array<String>) = runBlocking<Unit> {
1299 val channel = Channel<Int>(4) // create buffered channel
1300 launch(context) { // launch sender coroutine
1301 repeat(10) {
1302 println("Sending $it") // print before sending each element
1303 channel.send(it) // will suspend when buffer is full
1304 }
1305 }
1306 // don't receive anything... just wait....
1307 delay(1000)
1308}
1309```
1310
1311> You can get full code [here](kotlinx-coroutines-core/src/test/kotlin/guide/example-channel-08.kt)
1312
1313It prints "sending" _five_ times using a buffered channel with capacity of _four_:
1314
1315```
1316Sending 0
1317Sending 1
1318Sending 2
1319Sending 3
1320Sending 4
1321```
1322
1323The 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 +03001324
Roman Elizarove0c817d2017-02-10 10:22:01 +03001325<!--- SITE_ROOT https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core -->
1326<!--- DOCS_ROOT kotlinx-coroutines-core/target/dokka/kotlinx-coroutines-core -->
1327<!--- INDEX kotlinx.coroutines.experimental -->
Roman Elizarov419a6c82017-02-09 18:36:22 +03001328[CommonPool]: https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines.experimental/-common-pool/index.html
1329[CoroutineDispatcher]: https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines.experimental/-coroutine-dispatcher/index.html
1330[CoroutineName]: https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines.experimental/-coroutine-name/index.html
1331[CoroutineScope]: https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines.experimental/-coroutine-scope/index.html
Roman Elizarove0c817d2017-02-10 10:22:01 +03001332[CoroutineScope.context]: https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines.experimental/-coroutine-scope/context.html
1333[CoroutineScope.isActive]: https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines.experimental/-coroutine-scope/is-active.html
Roman Elizarov419a6c82017-02-09 18:36:22 +03001334[Deferred]: https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines.experimental/-deferred/index.html
Roman Elizarove0c817d2017-02-10 10:22:01 +03001335[Deferred.await]: https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines.experimental/-deferred/await.html
Roman Elizarov419a6c82017-02-09 18:36:22 +03001336[Job]: https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines.experimental/-job/index.html
Roman Elizarov2fd7cb32017-02-11 23:18:59 +03001337[Job.cancel]: https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines.experimental/-job/cancel.html
Roman Elizarove0c817d2017-02-10 10:22:01 +03001338[Job.start]: https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines.experimental/-job/start.html
Roman Elizarov2fd7cb32017-02-11 23:18:59 +03001339[Job.invoke]: https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines.experimental/-job/invoke.html
Roman Elizarov419a6c82017-02-09 18:36:22 +03001340[NonCancellable]: https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines.experimental/-non-cancellable/index.html
1341[Unconfined]: https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines.experimental/-unconfined/index.html
1342[CancellationException]: https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines.experimental/-cancellation-exception.html
1343[async]: https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines.experimental/async.html
1344[delay]: https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines.experimental/delay.html
1345[launch]: https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines.experimental/launch.html
1346[newCoroutineContext]: https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines.experimental/new-coroutine-context.html
1347[run]: https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines.experimental/run.html
1348[runBlocking]: https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines.experimental/run-blocking.html
1349[withTimeout]: https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines.experimental/with-timeout.html
1350[yield]: https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines.experimental/yield.html
Roman Elizarove0c817d2017-02-10 10:22:01 +03001351<!--- INDEX kotlinx.coroutines.experimental.channels -->
Roman Elizarov419a6c82017-02-09 18:36:22 +03001352[Channel]: https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines.experimental.channels/-channel/index.html
Roman Elizarove0c817d2017-02-10 10:22:01 +03001353[Channel.invoke]: https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines.experimental.channels/-channel/invoke.html
1354[ReceiveChannel.receive]: https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines.experimental.channels/-receive-channel/receive.html
1355[SendChannel.close]: https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines.experimental.channels/-send-channel/close.html
1356[SendChannel.send]: https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines.experimental.channels/-send-channel/send.html
Roman Elizarova5e653f2017-02-13 13:49:55 +03001357[produce]: https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines.experimental.channels/produce.html
Roman Elizarov419a6c82017-02-09 18:36:22 +03001358<!--- END -->