blob: 7d0304d852c702cb5dd5760809ce814874dc5655 [file] [log] [blame] [view]
Roman Elizarov7deefb82017-01-31 10:33:17 +03001# Guide to kotlinx.coroutines by example
2
3This is a short guide on core features of `kotlinx.coroutines` with a series of examples.
4
Roman Elizarov1293ccd2017-02-01 18:49:54 +03005## Table of contents
6
Roman Elizarovfa7723e2017-02-06 11:17:51 +03007<!--- TOC -->
8
Roman Elizarov1293ccd2017-02-01 18:49:54 +03009* [Coroutine basics](#coroutine-basics)
10 * [Your first coroutine](#your-first-coroutine)
11 * [Bridging blocking and non-blocking worlds](#bridging-blocking-and-non-blocking-worlds)
12 * [Waiting for a job](#waiting-for-a-job)
13 * [Extract function refactoring](#extract-function-refactoring)
14 * [Coroutines ARE light-weight](#coroutines-are-light-weight)
15 * [Coroutines are like daemon threads](#coroutines-are-like-daemon-threads)
16* [Cancellation and timeouts](#cancellation-and-timeouts)
17 * [Cancelling coroutine execution](#cancelling-coroutine-execution)
18 * [Cancellation is cooperative](#cancellation-is-cooperative)
19 * [Making computation code cancellable](#making-computation-code-cancellable)
20 * [Closing resources with finally](#closing-resources-with-finally)
21 * [Run non-cancellable block](#run-non-cancellable-block)
22 * [Timeout](#timeout)
23* [Composing suspending functions](#composing-suspending-functions)
24 * [Sequential by default](#sequential-by-default)
25 * [Concurrent using deferred value](#concurrent-using-deferred-value)
26 * [Lazily deferred value](#lazily-deferred-value)
Roman Elizarov2f6d7c92017-02-03 15:16:07 +030027* [Coroutine context and dispatchers](#coroutine-context-and-dispatchers)
Roman Elizarovfa7723e2017-02-06 11:17:51 +030028 * [Dispatchers and threads](#dispatchers-and-threads)
Roman Elizarov2f6d7c92017-02-03 15:16:07 +030029 * [Unconfined vs confined dispatcher](#unconfined-vs-confined-dispatcher)
30 * [Debugging coroutines and threads](#debugging-coroutines-and-threads)
31 * [Jumping between threads](#jumping-between-threads)
32 * [Job in the context](#job-in-the-context)
33 * [Children of a coroutine](#children-of-a-coroutine)
34 * [Combining contexts](#combining-contexts)
35 * [Naming coroutines for debugging](#naming-coroutines-for-debugging)
Roman Elizarovfa7723e2017-02-06 11:17:51 +030036
Roman Elizarovb3d55a52017-02-03 12:47:21 +030037<!--- KNIT kotlinx-coroutines-core/src/test/kotlin/guide/.*\.kt -->
Roman Elizarov1293ccd2017-02-01 18:49:54 +030038
Roman Elizarovfa7723e2017-02-06 11:17:51 +030039<!--- INCLUDE .*/example-([a-z]+)-([0-9]+)\.kt
Roman Elizarovb3d55a52017-02-03 12:47:21 +030040// This file was automatically generated from coroutines-guide.md by Knit tool. Do not edit.
Roman Elizarovfa7723e2017-02-06 11:17:51 +030041package guide.$$1.example$$2
Roman Elizarovb3d55a52017-02-03 12:47:21 +030042
43import kotlinx.coroutines.experimental.*
44-->
45
Roman Elizarov1293ccd2017-02-01 18:49:54 +030046## Coroutine basics
47
48This section covers basic coroutine concepts.
49
50### Your first coroutine
Roman Elizarov7deefb82017-01-31 10:33:17 +030051
52Run the following code:
53
54```kotlin
55fun main(args: Array<String>) {
56 launch(CommonPool) { // create new coroutine in common thread pool
57 delay(1000L) // non-blocking delay for 1 second (default time unit is ms)
58 println("World!") // print after delay
59 }
60 println("Hello,") // main function continues while coroutine is delayed
61 Thread.sleep(2000L) // block main thread for 2 seconds to keep JVM alive
62}
63```
64
Roman Elizarovfa7723e2017-02-06 11:17:51 +030065> You can get full code [here](kotlinx-coroutines-core/src/test/kotlin/guide/example-basic-01.kt)
Roman Elizarov7deefb82017-01-31 10:33:17 +030066
67Run this code:
68
69```
70Hello,
71World!
72```
73
74Essentially, coroutines are light-weight threads. You can achieve the same result replacing
75`launch(CommonPool) { ... }` with `thread { ... }` and `delay(...)` with `Thread.sleep(...)`. Try it.
76
77If you start by replacing `launch(CommonPool)` by `thread`, the compiler produces the following error:
78
79```
80Error: Kotlin: Suspend functions are only allowed to be called from a coroutine or another suspend function
81```
82
83That is because `delay` is a special _suspending function_ that does not block a thread, but _suspends_
84coroutine and it can be only used from a coroutine.
85
Roman Elizarov1293ccd2017-02-01 18:49:54 +030086### Bridging blocking and non-blocking worlds
Roman Elizarov7deefb82017-01-31 10:33:17 +030087
88The first example mixes _non-blocking_ `delay(...)` and _blocking_ `Thread.sleep(...)` in the same
89code of `main` function. It is easy to get lost. Let's cleanly separate blocking and non-blocking
90worlds by using `runBlocking { ... }`:
91
92```kotlin
93fun main(args: Array<String>) = runBlocking<Unit> { // start main coroutine
94 launch(CommonPool) { // create new coroutine in common thread pool
95 delay(1000L)
96 println("World!")
97 }
98 println("Hello,") // main coroutine continues while child is delayed
99 delay(2000L) // non-blocking delay for 2 seconds to keep JVM alive
100}
101```
102
Roman Elizarovfa7723e2017-02-06 11:17:51 +0300103> You can get full code [here](kotlinx-coroutines-core/src/test/kotlin/guide/example-basic-02.kt)
Roman Elizarov7deefb82017-01-31 10:33:17 +0300104
105The result is the same, but this code uses only non-blocking `delay`.
106
107`runBlocking { ... }` works as an adaptor that is used here to start the top-level main coroutine.
108The regular code outside of `runBlocking` _blocks_, until the coroutine inside `runBlocking` is active.
109
110This is also a way to write unit-tests for suspending functions:
111
112```kotlin
113class MyTest {
114 @Test
115 fun testMySuspendingFunction() = runBlocking<Unit> {
116 // here we can use suspending functions using any assertion style that we like
117 }
118}
119```
Roman Elizarovb3d55a52017-02-03 12:47:21 +0300120
121<!--- CLEAR -->
Roman Elizarov7deefb82017-01-31 10:33:17 +0300122
Roman Elizarov1293ccd2017-02-01 18:49:54 +0300123### Waiting for a job
Roman Elizarov7deefb82017-01-31 10:33:17 +0300124
Roman Elizarov1293ccd2017-02-01 18:49:54 +0300125Delaying for a time while another coroutine is working is not a good approach. Let's explicitly
126wait (in a non-blocking way) until the background job coroutine that we have launched is complete:
Roman Elizarov7deefb82017-01-31 10:33:17 +0300127
128```kotlin
129fun main(args: Array<String>) = runBlocking<Unit> {
130 val job = launch(CommonPool) { // create new coroutine and keep a reference to its Job
131 delay(1000L)
132 println("World!")
133 }
134 println("Hello,")
135 job.join() // wait until child coroutine completes
136}
137```
138
Roman Elizarovfa7723e2017-02-06 11:17:51 +0300139> You can get full code [here](kotlinx-coroutines-core/src/test/kotlin/guide/example-basic-03.kt)
Roman Elizarov7deefb82017-01-31 10:33:17 +0300140
141Now 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 +0300142the background job in any way. Much better.
Roman Elizarov7deefb82017-01-31 10:33:17 +0300143
Roman Elizarov1293ccd2017-02-01 18:49:54 +0300144### Extract function refactoring
Roman Elizarov7deefb82017-01-31 10:33:17 +0300145
146Let's extract the block of code inside `launch(CommonPool} { ... }` into a separate function. When you
147perform "Extract function" refactoring on this code you get a new function with `suspend` modifier.
148That is your first _suspending function_. Suspending functions can be used inside coroutines
149just like regular functions, but their additional feature is that they can, in turn,
150use other suspending functions, like `delay` in this example, to _suspend_ execution of a coroutine.
151
152```kotlin
153fun main(args: Array<String>) = runBlocking<Unit> {
154 val job = launch(CommonPool) { doWorld() }
155 println("Hello,")
156 job.join()
157}
158
159// this is your first suspending function
160suspend fun doWorld() {
161 delay(1000L)
162 println("World!")
163}
164```
165
Roman Elizarovfa7723e2017-02-06 11:17:51 +0300166> You can get full code [here](kotlinx-coroutines-core/src/test/kotlin/guide/example-basic-04.kt)
Roman Elizarov7deefb82017-01-31 10:33:17 +0300167
Roman Elizarov1293ccd2017-02-01 18:49:54 +0300168### Coroutines ARE light-weight
Roman Elizarov7deefb82017-01-31 10:33:17 +0300169
170Run the following code:
171
172```kotlin
173fun main(args: Array<String>) = runBlocking<Unit> {
174 val jobs = List(100_000) { // create a lot of coroutines and list their jobs
175 launch(CommonPool) {
176 delay(1000L)
177 print(".")
178 }
179 }
180 jobs.forEach { it.join() } // wait for all jobs to complete
181}
182```
183
Roman Elizarovfa7723e2017-02-06 11:17:51 +0300184> You can get full code [here](kotlinx-coroutines-core/src/test/kotlin/guide/example-basic-05.kt)
Roman Elizarov7deefb82017-01-31 10:33:17 +0300185
186It starts 100K coroutines and, after a second, each coroutine prints a dot.
187Now, try that with threads. What would happen? (Most likely your code will produce some sort of out-of-memory error)
188
Roman Elizarov1293ccd2017-02-01 18:49:54 +0300189### Coroutines are like daemon threads
Roman Elizarov7deefb82017-01-31 10:33:17 +0300190
191The following code launches a long-running coroutine that prints "I'm sleeping" twice a second and then
Roman Elizarov1293ccd2017-02-01 18:49:54 +0300192returns from the main function after some delay:
Roman Elizarov7deefb82017-01-31 10:33:17 +0300193
194```kotlin
195fun main(args: Array<String>) = runBlocking<Unit> {
196 launch(CommonPool) {
197 repeat(1000) { i ->
198 println("I'm sleeping $i ...")
199 delay(500L)
200 }
201 }
202 delay(1300L) // just quit after delay
203}
204```
205
Roman Elizarovfa7723e2017-02-06 11:17:51 +0300206> You can get full code [here](kotlinx-coroutines-core/src/test/kotlin/guide/example-basic-06.kt)
Roman Elizarov7deefb82017-01-31 10:33:17 +0300207
208You can run and see that it prints three lines and terminates:
209
210```
211I'm sleeping 0 ...
212I'm sleeping 1 ...
213I'm sleeping 2 ...
214```
215
216Active coroutines do not keep the process alive. They are like daemon threads.
217
Roman Elizarov1293ccd2017-02-01 18:49:54 +0300218## Cancellation and timeouts
219
220This section covers coroutine cancellation and timeouts.
221
222### Cancelling coroutine execution
Roman Elizarov7deefb82017-01-31 10:33:17 +0300223
224In small application the return from "main" method might sound like a good idea to get all coroutines
225implicitly terminated. In a larger, long-running application, you need finer-grained control.
226The `launch` function returns a `Job` that can be used to cancel running coroutine:
227
228```kotlin
229fun main(args: Array<String>) = runBlocking<Unit> {
230 val job = launch(CommonPool) {
231 repeat(1000) { i ->
232 println("I'm sleeping $i ...")
233 delay(500L)
234 }
235 }
236 delay(1300L) // delay a bit
Roman Elizarov1293ccd2017-02-01 18:49:54 +0300237 println("main: I'm tired of waiting!")
Roman Elizarov7deefb82017-01-31 10:33:17 +0300238 job.cancel() // cancels the job
239 delay(1300L) // delay a bit to ensure it was cancelled indeed
Roman Elizarov1293ccd2017-02-01 18:49:54 +0300240 println("main: Now I can quit.")
Roman Elizarov7deefb82017-01-31 10:33:17 +0300241}
242```
243
Roman Elizarovfa7723e2017-02-06 11:17:51 +0300244> You can get full code [here](kotlinx-coroutines-core/src/test/kotlin/guide/example-cancel-01.kt)
Roman Elizarov7deefb82017-01-31 10:33:17 +0300245
Roman Elizarov1293ccd2017-02-01 18:49:54 +0300246It produces the following output:
247
248```
249I'm sleeping 0 ...
250I'm sleeping 1 ...
251I'm sleeping 2 ...
252main: I'm tired of waiting!
253main: Now I can quit.
254```
255
256As soon as main invokes `job.cancel`, we don't see any output from the other coroutine because it was cancelled.
257
258### Cancellation is cooperative
Roman Elizarov7deefb82017-01-31 10:33:17 +0300259
Tair Rzayevaf734622017-02-01 22:30:16 +0200260Coroutine cancellation is _cooperative_. A coroutine code has to cooperate to be cancellable.
Roman Elizarov7deefb82017-01-31 10:33:17 +0300261All the suspending functions in `kotlinx.coroutines` are _cancellable_. They check for cancellation of
262coroutine and throw `CancellationException` when cancelled. However, if a coroutine is working in
263a computation and does not check for cancellation, then it cannot be cancelled, like the following
264example shows:
265
266```kotlin
267fun main(args: Array<String>) = runBlocking<Unit> {
268 val job = launch(CommonPool) {
269 var nextPrintTime = 0L
270 var i = 0
271 while (true) { // computation loop
272 val currentTime = System.currentTimeMillis()
273 if (currentTime >= nextPrintTime) {
274 println("I'm sleeping ${i++} ...")
275 nextPrintTime = currentTime + 500L
276 }
277 }
278 }
279 delay(1300L) // delay a bit
Roman Elizarov1293ccd2017-02-01 18:49:54 +0300280 println("main: I'm tired of waiting!")
Roman Elizarov7deefb82017-01-31 10:33:17 +0300281 job.cancel() // cancels the job
282 delay(1300L) // delay a bit to see if it was cancelled....
Roman Elizarov1293ccd2017-02-01 18:49:54 +0300283 println("main: Now I can quit.")
Roman Elizarov7deefb82017-01-31 10:33:17 +0300284}
285```
286
Roman Elizarovfa7723e2017-02-06 11:17:51 +0300287> You can get full code [here](kotlinx-coroutines-core/src/test/kotlin/guide/example-cancel-02.kt)
Roman Elizarov7deefb82017-01-31 10:33:17 +0300288
289Run it to see that it continues to print "I'm sleeping" even after cancellation.
290
Roman Elizarov1293ccd2017-02-01 18:49:54 +0300291### Making computation code cancellable
Roman Elizarov7deefb82017-01-31 10:33:17 +0300292
293There are two approaches to making computation code cancellable. The first one is to periodically
Roman Elizarov1293ccd2017-02-01 18:49:54 +0300294invoke a suspending function. There is a `yield` function that is a good choice for that purpose.
295The other one is to explicitly check the cancellation status. Let us try the later approach.
Roman Elizarov7deefb82017-01-31 10:33:17 +0300296
297Replace `while (true)` in the previous example with `while (isActive)` and rerun it.
298
Roman Elizarovb3d55a52017-02-03 12:47:21 +0300299```kotlin
300fun main(args: Array<String>) = runBlocking<Unit> {
301 val job = launch(CommonPool) {
302 var nextPrintTime = 0L
303 var i = 0
304 while (isActive) { // cancellable computation loop
305 val currentTime = System.currentTimeMillis()
306 if (currentTime >= nextPrintTime) {
307 println("I'm sleeping ${i++} ...")
308 nextPrintTime = currentTime + 500L
309 }
310 }
311 }
312 delay(1300L) // delay a bit
313 println("main: I'm tired of waiting!")
314 job.cancel() // cancels the job
315 delay(1300L) // delay a bit to see if it was cancelled....
316 println("main: Now I can quit.")
317}
318```
319
Roman Elizarovfa7723e2017-02-06 11:17:51 +0300320> You can get full code [here](kotlinx-coroutines-core/src/test/kotlin/guide/example-cancel-03.kt)
Roman Elizarov7deefb82017-01-31 10:33:17 +0300321
322As you can see, now this loop can be cancelled. `isActive` is a property that is available inside
323the code of coroutines via `CoroutineScope` object.
324
Roman Elizarov1293ccd2017-02-01 18:49:54 +0300325### Closing resources with finally
326
327Cancellable suspending functions throw `CancellationException` on cancellation which can be handled in
328all the usual way. For example, the `try {...} finally {...}` and Kotlin `use` function execute their
329finalization actions normally when coroutine is cancelled:
330
331```kotlin
332fun main(args: Array<String>) = runBlocking<Unit> {
333 val job = launch(CommonPool) {
334 try {
335 repeat(1000) { i ->
336 println("I'm sleeping $i ...")
337 delay(500L)
338 }
339 } finally {
340 println("I'm running finally")
341 }
342 }
343 delay(1300L) // delay a bit
344 println("main: I'm tired of waiting!")
345 job.cancel() // cancels the job
346 delay(1300L) // delay a bit to ensure it was cancelled indeed
347 println("main: Now I can quit.")
348}
349```
350
Roman Elizarovfa7723e2017-02-06 11:17:51 +0300351> You can get full code [here](kotlinx-coroutines-core/src/test/kotlin/guide/example-cancel-04.kt)
Roman Elizarov1293ccd2017-02-01 18:49:54 +0300352
353The example above produces the following output:
354
355```
356I'm sleeping 0 ...
357I'm sleeping 1 ...
358I'm sleeping 2 ...
359main: I'm tired of waiting!
360I'm running finally
361main: Now I can quit.
362```
363
364### Run non-cancellable block
365
366Any attempt to use a suspending function in the `finally` block of the previous example will cause
367`CancellationException`, because the coroutine running this code is cancelled. Usually, this is not a
368problem, since all well-behaving closing operations (closing a file, cancelling a job, or closing any kind of a
369communication channel) are usually non-blocking and do not involve any suspending functions. However, in the
370rare case when you need to suspend in the cancelled coroutine you can wrap the corresponding code in
371`run(NonCancellable) {...}` as the following example shows:
372
373```kotlin
374fun main(args: Array<String>) = runBlocking<Unit> {
375 val job = launch(CommonPool) {
376 try {
377 repeat(1000) { i ->
378 println("I'm sleeping $i ...")
379 delay(500L)
380 }
381 } finally {
382 run(NonCancellable) {
383 println("I'm running finally")
384 delay(1000L)
385 println("And I've just delayed for 1 sec because I'm non-cancellable")
386 }
387 }
388 }
389 delay(1300L) // delay a bit
390 println("main: I'm tired of waiting!")
391 job.cancel() // cancels the job
392 delay(1300L) // delay a bit to ensure it was cancelled indeed
393 println("main: Now I can quit.")
394}
395```
396
Roman Elizarovfa7723e2017-02-06 11:17:51 +0300397> You can get full code [here](kotlinx-coroutines-core/src/test/kotlin/guide/example-cancel-05.kt)
Roman Elizarov1293ccd2017-02-01 18:49:54 +0300398
399### Timeout
400
401The most obvious reason to cancel coroutine execution in practice,
402is because its execution time has exceeded some timeout.
403While you can manually track the reference to the corresponding `job` and launch a separate coroutine to cancel
404the tracked one after delay, there is a ready to use `withTimeout(...) {...}` function that does it.
405Look at the following example:
406
407```kotlin
408fun main(args: Array<String>) = runBlocking<Unit> {
409 withTimeout(1300L) {
410 repeat(1000) { i ->
411 println("I'm sleeping $i ...")
412 delay(500L)
413 }
414 }
415}
416```
417
Roman Elizarovfa7723e2017-02-06 11:17:51 +0300418> You can get full code [here](kotlinx-coroutines-core/src/test/kotlin/guide/example-cancel-06.kt)
Roman Elizarov1293ccd2017-02-01 18:49:54 +0300419
420It produces the following output:
421
422```
423I'm sleeping 0 ...
424I'm sleeping 1 ...
425I'm sleeping 2 ...
426Exception in thread "main" java.util.concurrent.CancellationException: Timed out waiting for 1300 MILLISECONDS
427```
428
429We have not seen the `CancellationException` stack trace printed on the console before. That is because
430inside a cancelled coroutine `CancellationException` is a considered a normal reason for coroutine completion.
431However, in this example we have used `withTimeout` right inside the `main` function.
432
433Because cancellation is just an exception, all the resources will be closed in a usual way.
434You can wrap the code with timeout in `try {...} catch (e: CancellationException) {...}` block if
435you need to do some additional action specifically on timeout.
436
437## Composing suspending functions
438
439This section covers various approaches to composition of suspending functions.
440
441### Sequential by default
442
443Assume that we have two suspending functions defined elsewhere that do something useful like some kind of
444remote service call or computation. We'll just pretend they are useful, but each one will just actaully
445delay for a second for the purpose of this example:
446
Roman Elizarovfa7723e2017-02-06 11:17:51 +0300447<!--- INCLUDE .*/example-compose-([0-9]+).kt
448import kotlin.system.measureTimeMillis
449-->
450
Roman Elizarov1293ccd2017-02-01 18:49:54 +0300451```kotlin
452suspend fun doSomethingUsefulOne(): Int {
453 delay(1000L) // pretend we are doing something useful here
454 return 13
455}
456
457suspend fun doSomethingUsefulTwo(): Int {
458 delay(1000L) // pretend we are doing something useful here, too
459 return 29
460}
461```
462
Roman Elizarovfa7723e2017-02-06 11:17:51 +0300463<!--- INCLUDE .*/example-compose-([0-9]+).kt -->
464
Roman Elizarov1293ccd2017-02-01 18:49:54 +0300465What do we do if need to invoke them _sequentially_ -- first `doSomethingUsefulOne` _and then_
466`doSomethingUsefulTwo` and compute the sum of their results?
467In practise we do this if we use the results of the first function to make a decision on whether we need
468to invoke the second one or to decide on how to invoke it.
469
470We just use a normal sequential invocation, because the code in the coroutine, just like in the regular
471code, is _sequential_ by default. The following example demonstrates that by measuring the total
472time it takes to execute both suspending functions:
473
474```kotlin
475fun main(args: Array<String>) = runBlocking<Unit> {
476 val time = measureTimeMillis {
477 val one = doSomethingUsefulOne()
478 val two = doSomethingUsefulTwo()
479 println("The answer is ${one + two}")
480 }
481 println("Completed in $time ms")
482}
483```
484
Roman Elizarovfa7723e2017-02-06 11:17:51 +0300485> You can get full code [here](kotlinx-coroutines-core/src/test/kotlin/guide/example-compose-01.kt)
Roman Elizarov1293ccd2017-02-01 18:49:54 +0300486
487It produces something like this:
488
489```
490The answer is 42
491Completed in 2017 ms
492```
493
494### Concurrent using deferred value
495
496What if there are no dependencies between invocation of `doSomethingUsefulOne` and `doSomethingUsefulTwo` and
497we want to get the answer faster, by doing both _concurrently_? This is where `defer` comes to helps.
498
499Conceptually, `defer` is just like `launch`. It starts a separate coroutine which is a light-weight thread
500that works concurrently with all the other coroutines. The difference is that `launch` returns a `Job` and
501does not carry any resulting value, while `defer` returns a `Deferred` -- a kind of light-weight non-blocking future
502that represent a promise to provide result later. You can use `.await()` on a deferred value to get its eventual result,
503but `Deferred` is also a `Job`, so you can cancel it if needed.
504
505```kotlin
506fun main(args: Array<String>) = runBlocking<Unit> {
507 val time = measureTimeMillis {
508 val one = defer(CommonPool) { doSomethingUsefulOne() }
509 val two = defer(CommonPool) { doSomethingUsefulTwo() }
510 println("The answer is ${one.await() + two.await()}")
511 }
512 println("Completed in $time ms")
513}
514```
515
Roman Elizarovfa7723e2017-02-06 11:17:51 +0300516> You can get full code [here](kotlinx-coroutines-core/src/test/kotlin/guide/example-compose-02.kt)
Roman Elizarov1293ccd2017-02-01 18:49:54 +0300517
518It produces something like this:
519
520```
521The answer is 42
522Completed in 1017 ms
523```
524
525This is twice as fast, because we have concurrent execution of two coroutines.
526Note, that concurrency with coroutines is always explicit.
527
528### Lazily deferred value
529
530There is a lazy alternative to `defer` that is called `lazyDefer`. It is just like `defer`, but it
531starts coroutine only when its result is needed by some `await` or if a special `start` function
532is invoked. Run the following example:
533
534```kotlin
535fun main(args: Array<String>) = runBlocking<Unit> {
536 val time = measureTimeMillis {
537 val one = lazyDefer(CommonPool) { doSomethingUsefulOne() }
538 val two = lazyDefer(CommonPool) { doSomethingUsefulTwo() }
539 println("The answer is ${one.await() + two.await()}")
540 }
541 println("Completed in $time ms")
542}
543```
544
Roman Elizarovfa7723e2017-02-06 11:17:51 +0300545> You can get full code [here](kotlinx-coroutines-core/src/test/kotlin/guide/example-compose-03.kt)
Roman Elizarov1293ccd2017-02-01 18:49:54 +0300546
547It produces something like this:
548
549```
550The answer is 42
551Completed in 2017 ms
552```
553
554So, we are back to two sequential execution, because we _first_ await for the `one` deferred, _and then_ await
555for the second one. It is not the intended use-case for `lazyDefer`. It is designed as a replacement for
556the standard `lazy` function in cases when computation of the value involve suspending functions.
557
Roman Elizarov2f6d7c92017-02-03 15:16:07 +0300558## Coroutine context and dispatchers
559
560We've already seen `launch(CommonPool) {...}`, `defer(CommonPool) {...}`, `run(NonCancellable) {...}`, etc.
561In these code snippets `CommonPool` and `NonCancellable` are _coroutine contexts_.
562This section covers other available choices.
563
564### Dispatchers and threads
565
566Coroutine context includes a _coroutine dispatcher_ which determines what thread or threads
567the corresponding coroutine uses for its execution. Coroutine dispatcher can confine coroutine execution
568to a specific thread, dispatch it to a thread pool, or let it run unconfined. Try the following example:
569
570```kotlin
571fun main(args: Array<String>) = runBlocking<Unit> {
572 val jobs = arrayListOf<Job>()
573 jobs += launch(Unconfined) { // not confined -- will work with main thread
574 println(" 'Unconfined': I'm working in thread ${Thread.currentThread().name}")
575 }
576 jobs += launch(context) { // context of the parent, runBlocking coroutine
577 println(" 'context': I'm working in thread ${Thread.currentThread().name}")
578 }
579 jobs += launch(CommonPool) { // will get dispatched to ForkJoinPool.commonPool (or equivalent)
580 println(" 'CommonPool': I'm working in thread ${Thread.currentThread().name}")
581 }
582 jobs += launch(newSingleThreadContext("MyOwnThread")) { // will get its own new thread
583 println(" 'newSTC': I'm working in thread ${Thread.currentThread().name}")
584 }
585 jobs.forEach { it.join() }
586}
587```
588
Roman Elizarovfa7723e2017-02-06 11:17:51 +0300589> You can get full code [here](kotlinx-coroutines-core/src/test/kotlin/guide/example-context-01.kt)
Roman Elizarov2f6d7c92017-02-03 15:16:07 +0300590
591It produces the following output (maybe in different order):
592
593```
594 'Unconfined': I'm working in thread main
595 'CommonPool': I'm working in thread ForkJoinPool.commonPool-worker-1
596 'newSTC': I'm working in thread MyOwnThread
597 'context': I'm working in thread main
598```
599
600The difference between parent `context` and `Unconfied` context will be shown later.
601
602### Unconfined vs confined dispatcher
603
604The `Unconfined` coroutine dispatcher starts coroutine in the caller thread, but only until the
605first suspension point. After suspension it resumes in the thread that is fully determined by the
606suspending function that was invoked. Unconfined dispatcher is appropriate when coroutine does not
607consume CPU time nor updates any shared data (like UI) that is confined to a specific thread.
608
609On the other side, `context` property that is available inside the block of any coroutine
610via `CoroutineScope` interface, is a reference to a context of this particular coroutine.
611This way, a parent context can be inherited. The default context of `runBlocking`, in particular,
612is confined to be invoker thread, so inheriting it has the effect of confining execution to
613this thread with a predictable FIFO scheduling.
614
615```kotlin
616fun main(args: Array<String>) = runBlocking<Unit> {
617 val jobs = arrayListOf<Job>()
618 jobs += launch(Unconfined) { // not confined -- will work with main thread
619 println(" 'Unconfined': I'm working in thread ${Thread.currentThread().name}")
620 delay(1000)
621 println(" 'Unconfined': After delay in thread ${Thread.currentThread().name}")
622 }
623 jobs += launch(context) { // context of the parent, runBlocking coroutine
624 println(" 'context': I'm working in thread ${Thread.currentThread().name}")
625 delay(1000)
626 println(" 'context': After delay in thread ${Thread.currentThread().name}")
627 }
628 jobs.forEach { it.join() }
629}
630```
631
Roman Elizarovfa7723e2017-02-06 11:17:51 +0300632> You can get full code [here](kotlinx-coroutines-core/src/test/kotlin/guide/example-contest-02.kt)
Roman Elizarov2f6d7c92017-02-03 15:16:07 +0300633
634Produces the output:
635
636```
637 'Unconfined': I'm working in thread main
638 'context': I'm working in thread main
639 'Unconfined': After delay in thread kotlinx.coroutines.ScheduledExecutor
640 'context': After delay in thread main
641```
642
643So, the coroutine the had inherited `context` of `runBlocking {...}` continues to execute in the `main` thread,
644while the unconfined one had resumed in the scheduler thread that `delay` function is using.
645
646### Debugging coroutines and threads
647
648Coroutines can suspend on one thread and resume on another thread with `Unconfined` dispatcher or
649with a multi-threaded dispatcher like `CommonPool`. Even with a single-threaded dispatcher it might be hard to
650figure out what coroutine was doing what, where, and when. The common approach to debugging applications with
651threads is to print the thread name in the log file on each log statement. This feature is universally supported
652by logging frameworks. When using coroutines, the thread name alone does not give much of a context, so
653`kotlinx.coroutines` includes debugging facilities to make it easier.
654
655Run the following code with `-Dkotlinx.coroutines.debug` JVM option:
656
657```kotlin
658fun log(msg: String) = println("[${Thread.currentThread().name}] $msg")
659
660fun main(args: Array<String>) = runBlocking<Unit> {
661 val a = defer(context) {
662 log("I'm computing a piece of the answer")
663 6
664 }
665 val b = defer(context) {
666 log("I'm computing another piece of the answer")
667 7
668 }
669 log("The answer is ${a.await() * b.await()}")
670}
671```
672
Roman Elizarovfa7723e2017-02-06 11:17:51 +0300673> You can get full code [here](kotlinx-coroutines-core/src/test/kotlin/guide/example-context-03.kt)
Roman Elizarov2f6d7c92017-02-03 15:16:07 +0300674
675There are three coroutines. The main couroutine (#1) -- `runBlocking` one,
676and two coroutines computing deferred values `a` (#2) and `b` (#3).
677They are all executing in the context of `runBlocking` and are confined to the main thread.
678The output of this code is:
679
680```
681[main @coroutine#2] I'm computing a piece of the answer
682[main @coroutine#3] I'm computing another piece of the answer
683[main @coroutine#1] The answer is 42
684```
685
686The `log` function prints the name of the thread in square brackets and you can see, that it is the `main`
687thread, but the identifier of the currently executing coroutine is appended to it. This identifier
688is consecutively assigned to all created coroutines when debugging mode is turned on.
689
690You can read more about debugging facilities in documentation for `newCoroutineContext` function.
691
692### Jumping between threads
693
694Run the following code with `-Dkotlinx.coroutines.debug` JVM option:
695
696```kotlin
697fun log(msg: String) = println("[${Thread.currentThread().name}] $msg")
698
699fun main(args: Array<String>) {
700 val ctx1 = newSingleThreadContext("Ctx1")
701 val ctx2 = newSingleThreadContext("Ctx2")
702 runBlocking(ctx1) {
703 log("Started in ctx1")
704 run(ctx2) {
705 log("Working in ctx2")
706 }
707 log("Back to ctx1")
708 }
709}
710```
711
Roman Elizarovfa7723e2017-02-06 11:17:51 +0300712> You can get full code [here](kotlinx-coroutines-core/src/test/kotlin/guide/example-context-04.kt)
Roman Elizarov2f6d7c92017-02-03 15:16:07 +0300713
714It demonstrates two new techniques. One is using `runBlocking` with an explicitly specified context, and
715the second one is using `run(context) {...}` to change a context of a coroutine while still staying in the
716same coroutine as you can see in the output below:
717
718```
719[Ctx1 @coroutine#1] Started in ctx1
720[Ctx2 @coroutine#1] Working in ctx2
721[Ctx1 @coroutine#1] Back to ctx1
722```
723
724### Job in the context
725
726The coroutine `Job` is part of its context. The coroutine can retrieve it from its own context
727using `context[Job]` expression:
728
729```kotlin
730fun main(args: Array<String>) = runBlocking<Unit> {
731 println("My job is ${context[Job]}")
732}
733```
734
Roman Elizarovfa7723e2017-02-06 11:17:51 +0300735> You can get full code [here](kotlinx-coroutines-core/src/test/kotlin/guide/example-context-05.kt)
Roman Elizarov2f6d7c92017-02-03 15:16:07 +0300736
737It produces
738
739```
740My job is BlockingCoroutine{isActive=true}
741```
742
743So, `isActive` in `CoroutineScope` is just a convenient shortcut for `context[Job]!!.isActive`.
744
745### Children of a coroutine
746
747When `context` of a coroutine is used to launch another coroutine, the `Job` of the new coroutine becomes
748a _child_ of the parent coroutine's job. When the parent coroutine is cancelled, all its children
749are recursively cancelled, too.
750
751```kotlin
752fun main(args: Array<String>) = runBlocking<Unit> {
753 // start a coroutine to process some kind of incoming request
754 val request = launch(CommonPool) {
755 // it spawns two other jobs, one with its separate context
756 val job1 = launch(CommonPool) {
757 println("job1: I have my own context and execute independently!")
758 delay(1000)
759 println("job1: I am not affected by cancellation of the request")
760 }
761 // and the other inherits the parent context
762 val job2 = launch(context) {
763 println("job2: I am a child of the request coroutine")
764 delay(1000)
765 println("job2: I will not execute this line if my parent request is cancelled")
766 }
767 // request completes when both its sub-jobs complete:
768 job1.join()
769 job2.join()
770 }
771 delay(500)
772 request.cancel() // cancel processing of the request
773 delay(1000) // delay a second to see what happens
774 println("main: Who has survived request cancellation?")
775}
776```
777
Roman Elizarovfa7723e2017-02-06 11:17:51 +0300778> You can get full code [here](kotlinx-coroutines-core/src/test/kotlin/guide/example-context-06.kt)
Roman Elizarov2f6d7c92017-02-03 15:16:07 +0300779
780The output of this code is:
781
782```
783job1: I have my own context and execute independently!
784job2: I am a child of the request coroutine
785job1: I am not affected by cancellation of the request
786main: Who has survived request cancellation?
787```
788
789### Combining contexts
790
791Coroutine context can be combined using `+` operator. The context on the right-hand side replaces relevant entries
792of the context on the left-hand side. For example, a `Job` of the parent coroutine can be inherited, while
793its dispatcher replaced:
794
795```kotlin
796fun main(args: Array<String>) = runBlocking<Unit> {
797 // start a coroutine to process some kind of incoming request
798 val request = launch(context) { // use the context of `runBlocking`
799 // spawns CPU-intensive child job in CommonPool !!!
800 val job = launch(context + CommonPool) {
801 println("job: I am a child of the request coroutine, but with a different dispatcher")
802 delay(1000)
803 println("job: I will not execute this line if my parent request is cancelled")
804 }
805 job.join() // request completes when its sub-job completes
806 }
807 delay(500)
808 request.cancel() // cancel processing of the request
809 delay(1000) // delay a second to see what happens
810 println("main: Who has survived request cancellation?")
811}
812```
813
Roman Elizarovfa7723e2017-02-06 11:17:51 +0300814> You can get full code [here](kotlinx-coroutines-core/src/test/kotlin/guide/example-context-07.kt)
Roman Elizarov2f6d7c92017-02-03 15:16:07 +0300815
816The expected outcome of this code is:
817
818```
819job: I am a child of the request coroutine, but with a different dispatcher
820main: Who has survived request cancellation?
821```
822
823### Naming coroutines for debugging
824
825Automatically assignmed ids are good when coroutines log often and you just need to correlate log records
826coming from the same coroutine. However, when coroutine is tied to the processing of a specific request
827or doing some specific background task, it is better to name it explicitly for debugging purposes.
828Coroutine name serves the same function as a thread name. It'll get displayed in the thread name that
829is executing this coroutine when debugging more is turned on.
830
831The following example demonstrates this concept:
832
833```kotlin
834fun log(msg: String) = println("[${Thread.currentThread().name}] $msg")
835
836fun main(args: Array<String>) = runBlocking(CoroutineName("main")) {
837 log("Started main coroutine")
838 // run two background value computations
839 val v1 = defer(CommonPool + CoroutineName("v1coroutine")) {
840 log("Computing v1")
841 delay(500)
842 252
843 }
844 val v2 = defer(CommonPool + CoroutineName("v2coroutine")) {
845 log("Computing v2")
846 delay(1000)
847 6
848 }
849 log("The answer for v1 / v2 = ${v1.await() / v2.await()}")
850}
851```
852
Roman Elizarovfa7723e2017-02-06 11:17:51 +0300853> You can get full code [here](kotlinx-coroutines-core/src/test/kotlin/guide/example-context-08.kt)
Roman Elizarov2f6d7c92017-02-03 15:16:07 +0300854
855The output it produces with `-Dkotlinx.coroutines.debug` JVM option is similar to:
856
857```
858[main @main#1] Started main coroutine
859[ForkJoinPool.commonPool-worker-1 @v1coroutine#2] Computing v1
860[ForkJoinPool.commonPool-worker-2 @v2coroutine#3] Computing v2
861[main @main#1] The answer for v1 / v2 = 42
862```
Roman Elizarov1293ccd2017-02-01 18:49:54 +0300863
Roman Elizarov7deefb82017-01-31 10:33:17 +0300864