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