blob: 6c3c0caa783ca9e3a337ea41d81fce4d7bdb361d [file] [log] [blame] [view]
hadihariri7db55532018-09-15 10:35:08 +02001<!--- INCLUDE .*/example-([a-z]+)-([0-9a-z]+)\.kt
2/*
Roman Elizarovdb0ef0c2019-07-03 15:02:44 +03003 * Copyright 2016-2019 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
hadihariri7db55532018-09-15 10:35:08 +02004 */
5
6// This file was automatically generated from coroutines-guide.md by Knit tool. Do not edit.
Roman Elizarov0950dfa2018-07-13 10:33:25 +03007package kotlinx.coroutines.guide.$$1$$2
hadihariri7db55532018-09-15 10:35:08 +02008-->
Vsevolod Tolstopyatove50a0fa2019-01-28 11:34:24 +03009<!--- KNIT ../kotlinx-coroutines-core/jvm/test/guide/.*\.kt -->
10<!--- TEST_OUT ../kotlinx-coroutines-core/jvm/test/guide/test/BasicsGuideTest.kt
hadihariri7db55532018-09-15 10:35:08 +020011// This file was automatically generated from coroutines-guide.md by Knit tool. Do not edit.
Roman Elizarov0950dfa2018-07-13 10:33:25 +030012package kotlinx.coroutines.guide.test
hadihariri7db55532018-09-15 10:35:08 +020013
14import org.junit.Test
15
16class BasicsGuideTest {
17-->
18
Prendotab8a559d2018-11-30 16:24:23 +030019**Table of contents**
hadihariri7db55532018-09-15 10:35:08 +020020
21<!--- TOC -->
22
Roman Elizarov3258e1f2019-08-22 20:08:48 +030023* [Coroutine Basics](#coroutine-basics)
hadihariri7db55532018-09-15 10:35:08 +020024 * [Your first coroutine](#your-first-coroutine)
25 * [Bridging blocking and non-blocking worlds](#bridging-blocking-and-non-blocking-worlds)
26 * [Waiting for a job](#waiting-for-a-job)
27 * [Structured concurrency](#structured-concurrency)
28 * [Scope builder](#scope-builder)
29 * [Extract function refactoring](#extract-function-refactoring)
30 * [Coroutines ARE light-weight](#coroutines-are-light-weight)
31 * [Global coroutines are like daemon threads](#global-coroutines-are-like-daemon-threads)
32
33<!--- END_TOC -->
34
35
Roman Elizarov3258e1f2019-08-22 20:08:48 +030036## Coroutine Basics
hadihariri7db55532018-09-15 10:35:08 +020037
38This section covers basic coroutine concepts.
39
40### Your first coroutine
41
42Run the following code:
43
Prendota65e6c8c2018-10-17 11:51:08 +030044<div class="sample" markdown="1" theme="idea" data-min-compiler-version="1.3">
Alexander Prendotacbeef102018-09-27 18:42:04 +030045
hadihariri7db55532018-09-15 10:35:08 +020046```kotlin
Prendota65e6c8c2018-10-17 11:51:08 +030047import kotlinx.coroutines.*
48
49fun main() {
Inego69c26df2019-04-21 14:51:25 +070050 GlobalScope.launch { // launch a new coroutine in background and continue
hadihariri7db55532018-09-15 10:35:08 +020051 delay(1000L) // non-blocking delay for 1 second (default time unit is ms)
52 println("World!") // print after delay
53 }
54 println("Hello,") // main thread continues while coroutine is delayed
55 Thread.sleep(2000L) // block main thread for 2 seconds to keep JVM alive
56}
57```
58
Alexander Prendotacbeef102018-09-27 18:42:04 +030059</div>
60
Inego69c26df2019-04-21 14:51:25 +070061> You can get full code [here](../kotlinx-coroutines-core/jvm/test/guide/example-basic-01.kt).
hadihariri7db55532018-09-15 10:35:08 +020062
Marcin Moskałae5bf9ae2018-10-08 09:59:41 +030063You will see the following result:
hadihariri7db55532018-09-15 10:35:08 +020064
65```text
66Hello,
67World!
68```
69
70<!--- TEST -->
71
72Essentially, coroutines are light-weight threads.
73They are launched with [launch] _coroutine builder_ in a context of some [CoroutineScope].
74Here we are launching a new coroutine in the [GlobalScope], meaning that the lifetime of the new
75coroutine is limited only by the lifetime of the whole application.
76
77You can achieve the same result replacing
Vsevolod Tolstopyatov445e0262019-11-25 18:56:24 +030078`GlobalScope.launch { ... }` with `thread { ... }` and `delay(...)` with `Thread.sleep(...)`.
79Try it (don't forget to import `kotlin.concurrent.thread`).
hadihariri7db55532018-09-15 10:35:08 +020080
81If you start by replacing `GlobalScope.launch` by `thread`, the compiler produces the following error:
82
83```
84Error: Kotlin: Suspend functions are only allowed to be called from a coroutine or another suspend function
85```
86
87That is because [delay] is a special _suspending function_ that does not block a thread, but _suspends_
88coroutine and it can be only used from a coroutine.
89
90### Bridging blocking and non-blocking worlds
91
92The first example mixes _non-blocking_ `delay(...)` and _blocking_ `Thread.sleep(...)` in the same code.
Devin Bb104cfc2018-11-12 11:51:00 -050093It is easy to lose track of which one is blocking and which one is not.
hadihariri7db55532018-09-15 10:35:08 +020094Let's be explicit about blocking using [runBlocking] coroutine builder:
95
Prendota65e6c8c2018-10-17 11:51:08 +030096<div class="sample" markdown="1" theme="idea" data-min-compiler-version="1.3">
Alexander Prendotacbeef102018-09-27 18:42:04 +030097
hadihariri7db55532018-09-15 10:35:08 +020098```kotlin
Prendota65e6c8c2018-10-17 11:51:08 +030099import kotlinx.coroutines.*
100
101fun main() {
Inego69c26df2019-04-21 14:51:25 +0700102 GlobalScope.launch { // launch a new coroutine in background and continue
hadihariri7db55532018-09-15 10:35:08 +0200103 delay(1000L)
104 println("World!")
105 }
106 println("Hello,") // main thread continues here immediately
107 runBlocking { // but this expression blocks the main thread
108 delay(2000L) // ... while we delay for 2 seconds to keep JVM alive
109 }
110}
111```
112
Alexander Prendotacbeef102018-09-27 18:42:04 +0300113</div>
114
Inego69c26df2019-04-21 14:51:25 +0700115> You can get full code [here](../kotlinx-coroutines-core/jvm/test/guide/example-basic-02.kt).
hadihariri7db55532018-09-15 10:35:08 +0200116
117<!--- TEST
118Hello,
119World!
120-->
121
122The result is the same, but this code uses only non-blocking [delay].
Inego596187e2019-04-21 14:21:53 +0700123The main thread invoking `runBlocking` _blocks_ until the coroutine inside `runBlocking` completes.
hadihariri7db55532018-09-15 10:35:08 +0200124
125This example can be also rewritten in a more idiomatic way, using `runBlocking` to wrap
126the execution of the main function:
127
Prendota65e6c8c2018-10-17 11:51:08 +0300128<div class="sample" markdown="1" theme="idea" data-min-compiler-version="1.3">
Alexander Prendotacbeef102018-09-27 18:42:04 +0300129
hadihariri7db55532018-09-15 10:35:08 +0200130```kotlin
Prendota65e6c8c2018-10-17 11:51:08 +0300131import kotlinx.coroutines.*
132
133fun main() = runBlocking<Unit> { // start main coroutine
Inego69c26df2019-04-21 14:51:25 +0700134 GlobalScope.launch { // launch a new coroutine in background and continue
hadihariri7db55532018-09-15 10:35:08 +0200135 delay(1000L)
136 println("World!")
137 }
138 println("Hello,") // main coroutine continues here immediately
139 delay(2000L) // delaying for 2 seconds to keep JVM alive
140}
141```
142
Alexander Prendotacbeef102018-09-27 18:42:04 +0300143</div>
144
Inego69c26df2019-04-21 14:51:25 +0700145> You can get full code [here](../kotlinx-coroutines-core/jvm/test/guide/example-basic-02b.kt).
hadihariri7db55532018-09-15 10:35:08 +0200146
147<!--- TEST
148Hello,
149World!
150-->
151
152Here `runBlocking<Unit> { ... }` works as an adaptor that is used to start the top-level main coroutine.
153We explicitly specify its `Unit` return type, because a well-formed `main` function in Kotlin has to return `Unit`.
154
Inego596187e2019-04-21 14:21:53 +0700155This is also a way to write unit tests for suspending functions:
Alexander Prendotacbeef102018-09-27 18:42:04 +0300156
Prendota65e6c8c2018-10-17 11:51:08 +0300157<!--- INCLUDE
158import kotlinx.coroutines.*
159-->
160
Alexander Prendotacbeef102018-09-27 18:42:04 +0300161<div class="sample" markdown="1" theme="idea" data-highlight-only>
hadihariri7db55532018-09-15 10:35:08 +0200162
163```kotlin
164class MyTest {
165 @Test
166 fun testMySuspendingFunction() = runBlocking<Unit> {
167 // here we can use suspending functions using any assertion style that we like
168 }
169}
170```
171
Alexander Prendotacbeef102018-09-27 18:42:04 +0300172</div>
173
hadihariri7db55532018-09-15 10:35:08 +0200174<!--- CLEAR -->
175
176### Waiting for a job
177
178Delaying for a time while another coroutine is working is not a good approach. Let's explicitly
179wait (in a non-blocking way) until the background [Job] that we have launched is complete:
180
Prendota65e6c8c2018-10-17 11:51:08 +0300181<div class="sample" markdown="1" theme="idea" data-min-compiler-version="1.3">
Alexander Prendotacbeef102018-09-27 18:42:04 +0300182
hadihariri7db55532018-09-15 10:35:08 +0200183```kotlin
Prendota65e6c8c2018-10-17 11:51:08 +0300184import kotlinx.coroutines.*
185
186fun main() = runBlocking {
187//sampleStart
Inego69c26df2019-04-21 14:51:25 +0700188 val job = GlobalScope.launch { // launch a new coroutine and keep a reference to its Job
hadihariri7db55532018-09-15 10:35:08 +0200189 delay(1000L)
190 println("World!")
191 }
192 println("Hello,")
193 job.join() // wait until child coroutine completes
Prendota65e6c8c2018-10-17 11:51:08 +0300194//sampleEnd
hadihariri7db55532018-09-15 10:35:08 +0200195}
196```
197
Alexander Prendotacbeef102018-09-27 18:42:04 +0300198</div>
199
Inego69c26df2019-04-21 14:51:25 +0700200> You can get full code [here](../kotlinx-coroutines-core/jvm/test/guide/example-basic-03.kt).
hadihariri7db55532018-09-15 10:35:08 +0200201
202<!--- TEST
203Hello,
204World!
205-->
206
207Now the result is still the same, but the code of the main coroutine is not tied to the duration of
208the background job in any way. Much better.
209
210### Structured concurrency
211
212There is still something to be desired for practical usage of coroutines.
Inego596187e2019-04-21 14:21:53 +0700213When we use `GlobalScope.launch`, we create a top-level coroutine. Even though it is light-weight, it still
hadihariri7db55532018-09-15 10:35:08 +0200214consumes some memory resources while it runs. If we forget to keep a reference to the newly launched
215coroutine it still runs. What if the code in the coroutine hangs (for example, we erroneously
216delay for too long), what if we launched too many coroutines and ran out of memory?
Inego596187e2019-04-21 14:21:53 +0700217Having to manually keep references to all the launched coroutines and [join][Job.join] them is error-prone.
hadihariri7db55532018-09-15 10:35:08 +0200218
219There is a better solution. We can use structured concurrency in our code.
220Instead of launching coroutines in the [GlobalScope], just like we usually do with threads (threads are always global),
221we can launch coroutines in the specific scope of the operation we are performing.
222
223In our example, we have `main` function that is turned into a coroutine using [runBlocking] coroutine builder.
saied89a223f352018-10-30 22:44:20 +0330224Every coroutine builder, including `runBlocking`, adds an instance of [CoroutineScope] to the scope of its code block.
hadihariri7db55532018-09-15 10:35:08 +0200225We can launch coroutines in this scope without having to `join` them explicitly, because
226an outer coroutine (`runBlocking` in our example) does not complete until all the coroutines launched
227in its scope complete. Thus, we can make our example simpler:
228
Prendota65e6c8c2018-10-17 11:51:08 +0300229<div class="sample" markdown="1" theme="idea" data-min-compiler-version="1.3">
Alexander Prendotacbeef102018-09-27 18:42:04 +0300230
hadihariri7db55532018-09-15 10:35:08 +0200231```kotlin
Prendota65e6c8c2018-10-17 11:51:08 +0300232import kotlinx.coroutines.*
233
234fun main() = runBlocking { // this: CoroutineScope
Inego69c26df2019-04-21 14:51:25 +0700235 launch { // launch a new coroutine in the scope of runBlocking
hadihariri7db55532018-09-15 10:35:08 +0200236 delay(1000L)
237 println("World!")
238 }
239 println("Hello,")
240}
241```
242
Alexander Prendotacbeef102018-09-27 18:42:04 +0300243</div>
244
Inego69c26df2019-04-21 14:51:25 +0700245> You can get full code [here](../kotlinx-coroutines-core/jvm/test/guide/example-basic-03s.kt).
hadihariri7db55532018-09-15 10:35:08 +0200246
247<!--- TEST
248Hello,
249World!
250-->
251
252### Scope builder
253In addition to the coroutine scope provided by different builders, it is possible to declare your own scope using
Inego6da0ccd2019-04-21 14:26:40 +0700254[coroutineScope] builder. It creates a coroutine scope and does not complete until all launched children
Vsevolod Tolstopyatove303e6b2019-10-09 13:55:57 +0300255complete.
256
257[runBlocking] and [coroutineScope] may look similar because they both wait for its body and all its children to complete.
258The main difference between these two is that the [runBlocking] method _blocks_ the current thread for waiting,
259while [coroutineScope] just suspends, releasing the underlying thread for other usages.
260Because of that difference, [runBlocking] is a regular function and [coroutineScope] is a suspending function.
261
262It can be demonstrated by the following example:
hadihariri7db55532018-09-15 10:35:08 +0200263
Prendota65e6c8c2018-10-17 11:51:08 +0300264<div class="sample" markdown="1" theme="idea" data-min-compiler-version="1.3">
Alexander Prendotacbeef102018-09-27 18:42:04 +0300265
hadihariri7db55532018-09-15 10:35:08 +0200266```kotlin
Prendota65e6c8c2018-10-17 11:51:08 +0300267import kotlinx.coroutines.*
268
269fun main() = runBlocking { // this: CoroutineScope
hadihariri7db55532018-09-15 10:35:08 +0200270 launch {
271 delay(200L)
272 println("Task from runBlocking")
273 }
274
Inego564a5a62019-04-21 14:34:55 +0700275 coroutineScope { // Creates a coroutine scope
hadihariri7db55532018-09-15 10:35:08 +0200276 launch {
277 delay(500L)
278 println("Task from nested launch")
279 }
280
281 delay(100L)
Inego69c26df2019-04-21 14:51:25 +0700282 println("Task from coroutine scope") // This line will be printed before the nested launch
hadihariri7db55532018-09-15 10:35:08 +0200283 }
284
Inego69c26df2019-04-21 14:51:25 +0700285 println("Coroutine scope is over") // This line is not printed until the nested launch completes
hadihariri7db55532018-09-15 10:35:08 +0200286}
287```
288
Alexander Prendotacbeef102018-09-27 18:42:04 +0300289</div>
290
Inego69c26df2019-04-21 14:51:25 +0700291> You can get full code [here](../kotlinx-coroutines-core/jvm/test/guide/example-basic-04.kt).
hadihariri7db55532018-09-15 10:35:08 +0200292
293<!--- TEST
294Task from coroutine scope
295Task from runBlocking
296Task from nested launch
297Coroutine scope is over
298-->
299
Vsevolod Tolstopyatove303e6b2019-10-09 13:55:57 +0300300Note that right after "Task from coroutine scope" message, while waiting for nested launch,
301 "Task from runBlocking" is executed and printed, though coroutineScope is not completed yet.
302
hadihariri7db55532018-09-15 10:35:08 +0200303### Extract function refactoring
304
305Let's extract the block of code inside `launch { ... }` into a separate function. When you
306perform "Extract function" refactoring on this code you get a new function with `suspend` modifier.
307That is your first _suspending function_. Suspending functions can be used inside coroutines
308just like regular functions, but their additional feature is that they can, in turn,
309use other suspending functions, like `delay` in this example, to _suspend_ execution of a coroutine.
310
Prendota65e6c8c2018-10-17 11:51:08 +0300311<div class="sample" markdown="1" theme="idea" data-min-compiler-version="1.3">
Alexander Prendotacbeef102018-09-27 18:42:04 +0300312
hadihariri7db55532018-09-15 10:35:08 +0200313```kotlin
Prendota65e6c8c2018-10-17 11:51:08 +0300314import kotlinx.coroutines.*
315
316fun main() = runBlocking {
hadihariri7db55532018-09-15 10:35:08 +0200317 launch { doWorld() }
318 println("Hello,")
319}
320
321// this is your first suspending function
322suspend fun doWorld() {
323 delay(1000L)
324 println("World!")
325}
326```
327
Alexander Prendotacbeef102018-09-27 18:42:04 +0300328</div>
329
Inego69c26df2019-04-21 14:51:25 +0700330> You can get full code [here](../kotlinx-coroutines-core/jvm/test/guide/example-basic-05.kt).
hadihariri7db55532018-09-15 10:35:08 +0200331
332<!--- TEST
333Hello,
334World!
335-->
336
337
338But what if the extracted function contains a coroutine builder which is invoked on the current scope?
Petter Måhlén61302382019-07-02 08:01:36 +0200339In this case `suspend` modifier on the extracted function is not enough. Making `doWorld` an extension
hadihariri7db55532018-09-15 10:35:08 +0200340method on `CoroutineScope` is one of the solutions, but it may not always be applicable as it does not make API clearer.
Inego69c26df2019-04-21 14:51:25 +0700341The idiomatic solution is to have either an explicit `CoroutineScope` as a field in a class containing the target function
342or an implicit one when the outer class implements `CoroutineScope`.
Vsevolod Tolstopyatovfac516f2018-09-28 14:38:29 +0300343As a last resort, [CoroutineScope(coroutineContext)][CoroutineScope()] can be used, but such approach is structurally unsafe
Inego69c26df2019-04-21 14:51:25 +0700344because you no longer have control on the scope of execution of this method. Only private APIs can use this builder.
hadihariri7db55532018-09-15 10:35:08 +0200345
346### Coroutines ARE light-weight
347
348Run the following code:
349
Alexander Prendotacbeef102018-09-27 18:42:04 +0300350<div class="sample" markdown="1" theme="idea" data-highlight-only>
351
hadihariri7db55532018-09-15 10:35:08 +0200352```kotlin
Prendota65e6c8c2018-10-17 11:51:08 +0300353import kotlinx.coroutines.*
354
355fun main() = runBlocking {
hadihariri7db55532018-09-15 10:35:08 +0200356 repeat(100_000) { // launch a lot of coroutines
357 launch {
358 delay(1000L)
359 print(".")
360 }
361 }
362}
363```
364
Alexander Prendotacbeef102018-09-27 18:42:04 +0300365</div>
366
Inego69c26df2019-04-21 14:51:25 +0700367> You can get full code [here](../kotlinx-coroutines-core/jvm/test/guide/example-basic-06.kt).
hadihariri7db55532018-09-15 10:35:08 +0200368
369<!--- TEST lines.size == 1 && lines[0] == ".".repeat(100_000) -->
370
371It launches 100K coroutines and, after a second, each coroutine prints a dot.
372Now, try that with threads. What would happen? (Most likely your code will produce some sort of out-of-memory error)
373
374### Global coroutines are like daemon threads
375
376The following code launches a long-running coroutine in [GlobalScope] that prints "I'm sleeping" twice a second and then
377returns from the main function after some delay:
378
Prendota65e6c8c2018-10-17 11:51:08 +0300379<div class="sample" markdown="1" theme="idea" data-min-compiler-version="1.3">
Alexander Prendotacbeef102018-09-27 18:42:04 +0300380
hadihariri7db55532018-09-15 10:35:08 +0200381```kotlin
Prendota65e6c8c2018-10-17 11:51:08 +0300382import kotlinx.coroutines.*
383
384fun main() = runBlocking {
385//sampleStart
hadihariri7db55532018-09-15 10:35:08 +0200386 GlobalScope.launch {
387 repeat(1000) { i ->
388 println("I'm sleeping $i ...")
389 delay(500L)
390 }
391 }
392 delay(1300L) // just quit after delay
Prendota65e6c8c2018-10-17 11:51:08 +0300393//sampleEnd
hadihariri7db55532018-09-15 10:35:08 +0200394}
395```
396
Alexander Prendotacbeef102018-09-27 18:42:04 +0300397</div>
398
Inego69c26df2019-04-21 14:51:25 +0700399> You can get full code [here](../kotlinx-coroutines-core/jvm/test/guide/example-basic-07.kt).
hadihariri7db55532018-09-15 10:35:08 +0200400
401You can run and see that it prints three lines and terminates:
402
403```text
404I'm sleeping 0 ...
405I'm sleeping 1 ...
406I'm sleeping 2 ...
407```
408
409<!--- TEST -->
410
411Active coroutines that were launched in [GlobalScope] do not keep the process alive. They are like daemon threads.
412
Roman Elizarov99c28aa2018-09-23 18:42:36 +0300413<!--- MODULE kotlinx-coroutines-core -->
Roman Elizarov0950dfa2018-07-13 10:33:25 +0300414<!--- INDEX kotlinx.coroutines -->
415[launch]: https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines/launch.html
416[CoroutineScope]: https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines/-coroutine-scope/index.html
417[GlobalScope]: https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines/-global-scope/index.html
418[delay]: https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines/delay.html
419[runBlocking]: https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines/run-blocking.html
420[Job]: https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines/-job/index.html
421[Job.join]: https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines/-job/join.html
422[coroutineScope]: https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines/coroutine-scope.html
423[CoroutineScope()]: https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines/-coroutine-scope.html
Roman Elizarov99c28aa2018-09-23 18:42:36 +0300424<!--- END -->
hadihariri7db55532018-09-15 10:35:08 +0200425
426