blob: 8aca23a18c1b7e84129699d00ff781b1483bf464 [file] [log] [blame] [view]
Roman Elizarov660c2d72020-02-14 13:18:37 +03001<!--- TEST_NAME BasicsGuideTest -->
hadihariri7db55532018-09-15 10:35:08 +02002
Prendotab8a559d2018-11-30 16:24:23 +03003**Table of contents**
hadihariri7db55532018-09-15 10:35:08 +02004
5<!--- TOC -->
6
Roman Elizarov3258e1f2019-08-22 20:08:48 +03007* [Coroutine Basics](#coroutine-basics)
hadihariri7db55532018-09-15 10:35:08 +02008 * [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 * [Structured concurrency](#structured-concurrency)
12 * [Scope builder](#scope-builder)
13 * [Extract function refactoring](#extract-function-refactoring)
14 * [Coroutines ARE light-weight](#coroutines-are-light-weight)
15 * [Global coroutines are like daemon threads](#global-coroutines-are-like-daemon-threads)
16
Roman Elizarov660c2d72020-02-14 13:18:37 +030017<!--- END -->
hadihariri7db55532018-09-15 10:35:08 +020018
Roman Elizarov3258e1f2019-08-22 20:08:48 +030019## Coroutine Basics
hadihariri7db55532018-09-15 10:35:08 +020020
21This section covers basic coroutine concepts.
22
23### Your first coroutine
24
25Run the following code:
26
Prendota65e6c8c2018-10-17 11:51:08 +030027<div class="sample" markdown="1" theme="idea" data-min-compiler-version="1.3">
Alexander Prendotacbeef102018-09-27 18:42:04 +030028
hadihariri7db55532018-09-15 10:35:08 +020029```kotlin
Prendota65e6c8c2018-10-17 11:51:08 +030030import kotlinx.coroutines.*
31
32fun main() {
Inego69c26df2019-04-21 14:51:25 +070033 GlobalScope.launch { // launch a new coroutine in background and continue
hadihariri7db55532018-09-15 10:35:08 +020034 delay(1000L) // non-blocking delay for 1 second (default time unit is ms)
35 println("World!") // print after delay
36 }
37 println("Hello,") // main thread continues while coroutine is delayed
38 Thread.sleep(2000L) // block main thread for 2 seconds to keep JVM alive
39}
40```
41
Alexander Prendotacbeef102018-09-27 18:42:04 +030042</div>
43
Adam Howardf13549a2020-06-02 11:17:46 +010044> You can get the full code [here](../kotlinx-coroutines-core/jvm/test/guide/example-basic-01.kt).
hadihariri7db55532018-09-15 10:35:08 +020045
Marcin Moskałae5bf9ae2018-10-08 09:59:41 +030046You will see the following result:
hadihariri7db55532018-09-15 10:35:08 +020047
48```text
49Hello,
50World!
51```
52
53<!--- TEST -->
54
55Essentially, coroutines are light-weight threads.
56They are launched with [launch] _coroutine builder_ in a context of some [CoroutineScope].
57Here we are launching a new coroutine in the [GlobalScope], meaning that the lifetime of the new
58coroutine is limited only by the lifetime of the whole application.
59
Adam Howardcdbdba92020-06-02 11:21:34 +010060You can achieve the same result by replacing
61`GlobalScope.launch { ... }` with `thread { ... }`, and `delay(...)` with `Thread.sleep(...)`.
Vsevolod Tolstopyatov445e0262019-11-25 18:56:24 +030062Try it (don't forget to import `kotlin.concurrent.thread`).
hadihariri7db55532018-09-15 10:35:08 +020063
Adam Howardcdbdba92020-06-02 11:21:34 +010064If you start by replacing `GlobalScope.launch` with `thread`, the compiler produces the following error:
hadihariri7db55532018-09-15 10:35:08 +020065
66```
67Error: Kotlin: Suspend functions are only allowed to be called from a coroutine or another suspend function
68```
69
Adam Howardcdbdba92020-06-02 11:21:34 +010070That is because [delay] is a special _suspending function_ that does not block a thread, but _suspends_ the
71coroutine, and it can be only used from a coroutine.
hadihariri7db55532018-09-15 10:35:08 +020072
73### Bridging blocking and non-blocking worlds
74
75The first example mixes _non-blocking_ `delay(...)` and _blocking_ `Thread.sleep(...)` in the same code.
Devin Bb104cfc2018-11-12 11:51:00 -050076It is easy to lose track of which one is blocking and which one is not.
Adam Howardcdbdba92020-06-02 11:21:34 +010077Let's be explicit about blocking using the [runBlocking] coroutine builder:
hadihariri7db55532018-09-15 10:35:08 +020078
Prendota65e6c8c2018-10-17 11:51:08 +030079<div class="sample" markdown="1" theme="idea" data-min-compiler-version="1.3">
Alexander Prendotacbeef102018-09-27 18:42:04 +030080
hadihariri7db55532018-09-15 10:35:08 +020081```kotlin
Prendota65e6c8c2018-10-17 11:51:08 +030082import kotlinx.coroutines.*
83
84fun main() {
Inego69c26df2019-04-21 14:51:25 +070085 GlobalScope.launch { // launch a new coroutine in background and continue
hadihariri7db55532018-09-15 10:35:08 +020086 delay(1000L)
87 println("World!")
88 }
89 println("Hello,") // main thread continues here immediately
90 runBlocking { // but this expression blocks the main thread
91 delay(2000L) // ... while we delay for 2 seconds to keep JVM alive
92 }
93}
94```
95
Alexander Prendotacbeef102018-09-27 18:42:04 +030096</div>
97
Adam Howardf13549a2020-06-02 11:17:46 +010098> You can get the full code [here](../kotlinx-coroutines-core/jvm/test/guide/example-basic-02.kt).
hadihariri7db55532018-09-15 10:35:08 +020099
100<!--- TEST
101Hello,
102World!
103-->
104
105The result is the same, but this code uses only non-blocking [delay].
Inego596187e2019-04-21 14:21:53 +0700106The main thread invoking `runBlocking` _blocks_ until the coroutine inside `runBlocking` completes.
hadihariri7db55532018-09-15 10:35:08 +0200107
108This example can be also rewritten in a more idiomatic way, using `runBlocking` to wrap
109the execution of the main function:
110
Prendota65e6c8c2018-10-17 11:51:08 +0300111<div class="sample" markdown="1" theme="idea" data-min-compiler-version="1.3">
Alexander Prendotacbeef102018-09-27 18:42:04 +0300112
hadihariri7db55532018-09-15 10:35:08 +0200113```kotlin
Prendota65e6c8c2018-10-17 11:51:08 +0300114import kotlinx.coroutines.*
115
116fun main() = runBlocking<Unit> { // start main coroutine
Inego69c26df2019-04-21 14:51:25 +0700117 GlobalScope.launch { // launch a new coroutine in background and continue
hadihariri7db55532018-09-15 10:35:08 +0200118 delay(1000L)
119 println("World!")
120 }
121 println("Hello,") // main coroutine continues here immediately
122 delay(2000L) // delaying for 2 seconds to keep JVM alive
123}
124```
125
Alexander Prendotacbeef102018-09-27 18:42:04 +0300126</div>
127
Adam Howardf13549a2020-06-02 11:17:46 +0100128> You can get the full code [here](../kotlinx-coroutines-core/jvm/test/guide/example-basic-03.kt).
hadihariri7db55532018-09-15 10:35:08 +0200129
130<!--- TEST
131Hello,
132World!
133-->
134
135Here `runBlocking<Unit> { ... }` works as an adaptor that is used to start the top-level main coroutine.
136We explicitly specify its `Unit` return type, because a well-formed `main` function in Kotlin has to return `Unit`.
137
Inego596187e2019-04-21 14:21:53 +0700138This is also a way to write unit tests for suspending functions:
Alexander Prendotacbeef102018-09-27 18:42:04 +0300139
Prendota65e6c8c2018-10-17 11:51:08 +0300140<!--- INCLUDE
141import kotlinx.coroutines.*
142-->
143
Alexander Prendotacbeef102018-09-27 18:42:04 +0300144<div class="sample" markdown="1" theme="idea" data-highlight-only>
hadihariri7db55532018-09-15 10:35:08 +0200145
146```kotlin
147class MyTest {
148 @Test
149 fun testMySuspendingFunction() = runBlocking<Unit> {
150 // here we can use suspending functions using any assertion style that we like
151 }
152}
153```
154
Alexander Prendotacbeef102018-09-27 18:42:04 +0300155</div>
156
hadihariri7db55532018-09-15 10:35:08 +0200157<!--- CLEAR -->
158
159### Waiting for a job
160
161Delaying for a time while another coroutine is working is not a good approach. Let's explicitly
162wait (in a non-blocking way) until the background [Job] that we have launched is complete:
163
Prendota65e6c8c2018-10-17 11:51:08 +0300164<div class="sample" markdown="1" theme="idea" data-min-compiler-version="1.3">
Alexander Prendotacbeef102018-09-27 18:42:04 +0300165
hadihariri7db55532018-09-15 10:35:08 +0200166```kotlin
Prendota65e6c8c2018-10-17 11:51:08 +0300167import kotlinx.coroutines.*
168
169fun main() = runBlocking {
170//sampleStart
Inego69c26df2019-04-21 14:51:25 +0700171 val job = GlobalScope.launch { // launch a new coroutine and keep a reference to its Job
hadihariri7db55532018-09-15 10:35:08 +0200172 delay(1000L)
173 println("World!")
174 }
175 println("Hello,")
176 job.join() // wait until child coroutine completes
Prendota65e6c8c2018-10-17 11:51:08 +0300177//sampleEnd
hadihariri7db55532018-09-15 10:35:08 +0200178}
179```
180
Alexander Prendotacbeef102018-09-27 18:42:04 +0300181</div>
182
Adam Howardf13549a2020-06-02 11:17:46 +0100183> You can get the full code [here](../kotlinx-coroutines-core/jvm/test/guide/example-basic-04.kt).
hadihariri7db55532018-09-15 10:35:08 +0200184
185<!--- TEST
186Hello,
187World!
188-->
189
190Now the result is still the same, but the code of the main coroutine is not tied to the duration of
191the background job in any way. Much better.
192
193### Structured concurrency
194
195There is still something to be desired for practical usage of coroutines.
Inego596187e2019-04-21 14:21:53 +0700196When we use `GlobalScope.launch`, we create a top-level coroutine. Even though it is light-weight, it still
hadihariri7db55532018-09-15 10:35:08 +0200197consumes some memory resources while it runs. If we forget to keep a reference to the newly launched
Adam Howardcdbdba92020-06-02 11:21:34 +0100198coroutine, it still runs. What if the code in the coroutine hangs (for example, we erroneously
hadihariri7db55532018-09-15 10:35:08 +0200199delay for too long), what if we launched too many coroutines and ran out of memory?
Inego596187e2019-04-21 14:21:53 +0700200Having to manually keep references to all the launched coroutines and [join][Job.join] them is error-prone.
hadihariri7db55532018-09-15 10:35:08 +0200201
202There is a better solution. We can use structured concurrency in our code.
203Instead of launching coroutines in the [GlobalScope], just like we usually do with threads (threads are always global),
204we can launch coroutines in the specific scope of the operation we are performing.
205
Adam Howardcdbdba92020-06-02 11:21:34 +0100206In our example, we have a `main` function that is turned into a coroutine using the [runBlocking] coroutine builder.
saied89a223f352018-10-30 22:44:20 +0330207Every coroutine builder, including `runBlocking`, adds an instance of [CoroutineScope] to the scope of its code block.
hadihariri7db55532018-09-15 10:35:08 +0200208We can launch coroutines in this scope without having to `join` them explicitly, because
209an outer coroutine (`runBlocking` in our example) does not complete until all the coroutines launched
210in its scope complete. Thus, we can make our example simpler:
211
Prendota65e6c8c2018-10-17 11:51:08 +0300212<div class="sample" markdown="1" theme="idea" data-min-compiler-version="1.3">
Alexander Prendotacbeef102018-09-27 18:42:04 +0300213
hadihariri7db55532018-09-15 10:35:08 +0200214```kotlin
Prendota65e6c8c2018-10-17 11:51:08 +0300215import kotlinx.coroutines.*
216
217fun main() = runBlocking { // this: CoroutineScope
Inego69c26df2019-04-21 14:51:25 +0700218 launch { // launch a new coroutine in the scope of runBlocking
hadihariri7db55532018-09-15 10:35:08 +0200219 delay(1000L)
220 println("World!")
221 }
222 println("Hello,")
223}
224```
225
Alexander Prendotacbeef102018-09-27 18:42:04 +0300226</div>
227
Adam Howardf13549a2020-06-02 11:17:46 +0100228> You can get the full code [here](../kotlinx-coroutines-core/jvm/test/guide/example-basic-05.kt).
hadihariri7db55532018-09-15 10:35:08 +0200229
230<!--- TEST
231Hello,
232World!
233-->
234
235### Scope builder
Vsevolod Tolstopyatove303e6b2019-10-09 13:55:57 +0300236
Adam Howardcdbdba92020-06-02 11:21:34 +0100237In addition to the coroutine scope provided by different builders, it is possible to declare your own scope using the
Roman Elizaroveb1b5db2020-10-16 10:45:08 +0300238[coroutineScope][_coroutineScope] builder. It creates a coroutine scope and does not complete until all launched children complete.
Adam Howardcdbdba92020-06-02 11:21:34 +0100239
Roman Elizaroveb1b5db2020-10-16 10:45:08 +0300240[runBlocking] and [coroutineScope][_coroutineScope] may look similar because they both wait for their body and all its children to complete.
Adam Howardcdbdba92020-06-02 11:21:34 +0100241The main difference is that the [runBlocking] method _blocks_ the current thread for waiting,
Roman Elizaroveb1b5db2020-10-16 10:45:08 +0300242while [coroutineScope][_coroutineScope] just suspends, releasing the underlying thread for other usages.
243Because of that difference, [runBlocking] is a regular function and [coroutineScope][_coroutineScope] is a suspending function.
Vsevolod Tolstopyatove303e6b2019-10-09 13:55:57 +0300244
245It can be demonstrated by the following example:
hadihariri7db55532018-09-15 10:35:08 +0200246
Prendota65e6c8c2018-10-17 11:51:08 +0300247<div class="sample" markdown="1" theme="idea" data-min-compiler-version="1.3">
Alexander Prendotacbeef102018-09-27 18:42:04 +0300248
hadihariri7db55532018-09-15 10:35:08 +0200249```kotlin
Prendota65e6c8c2018-10-17 11:51:08 +0300250import kotlinx.coroutines.*
251
252fun main() = runBlocking { // this: CoroutineScope
hadihariri7db55532018-09-15 10:35:08 +0200253 launch {
254 delay(200L)
255 println("Task from runBlocking")
256 }
257
Inego564a5a62019-04-21 14:34:55 +0700258 coroutineScope { // Creates a coroutine scope
hadihariri7db55532018-09-15 10:35:08 +0200259 launch {
260 delay(500L)
261 println("Task from nested launch")
262 }
263
264 delay(100L)
Inego69c26df2019-04-21 14:51:25 +0700265 println("Task from coroutine scope") // This line will be printed before the nested launch
hadihariri7db55532018-09-15 10:35:08 +0200266 }
267
Inego69c26df2019-04-21 14:51:25 +0700268 println("Coroutine scope is over") // This line is not printed until the nested launch completes
hadihariri7db55532018-09-15 10:35:08 +0200269}
270```
271
Alexander Prendotacbeef102018-09-27 18:42:04 +0300272</div>
273
Adam Howardf13549a2020-06-02 11:17:46 +0100274> You can get the full code [here](../kotlinx-coroutines-core/jvm/test/guide/example-basic-06.kt).
hadihariri7db55532018-09-15 10:35:08 +0200275
276<!--- TEST
277Task from coroutine scope
278Task from runBlocking
279Task from nested launch
280Coroutine scope is over
281-->
282
Adam Howardcdbdba92020-06-02 11:21:34 +0100283Note that right after the "Task from coroutine scope" message (while waiting for nested launch)
Roman Elizaroveb1b5db2020-10-16 10:45:08 +0300284 "Task from runBlocking" is executed and printed — even though the [coroutineScope][_coroutineScope] is not completed yet.
Vsevolod Tolstopyatove303e6b2019-10-09 13:55:57 +0300285
hadihariri7db55532018-09-15 10:35:08 +0200286### Extract function refactoring
287
288Let's extract the block of code inside `launch { ... }` into a separate function. When you
Adam Howardcdbdba92020-06-02 11:21:34 +0100289perform "Extract function" refactoring on this code, you get a new function with the `suspend` modifier.
290This is your first _suspending function_. Suspending functions can be used inside coroutines
hadihariri7db55532018-09-15 10:35:08 +0200291just like regular functions, but their additional feature is that they can, in turn,
Adam Howardcdbdba92020-06-02 11:21:34 +0100292use other suspending functions (like `delay` in this example) to _suspend_ execution of a coroutine.
hadihariri7db55532018-09-15 10:35:08 +0200293
Prendota65e6c8c2018-10-17 11:51:08 +0300294<div class="sample" markdown="1" theme="idea" data-min-compiler-version="1.3">
Alexander Prendotacbeef102018-09-27 18:42:04 +0300295
hadihariri7db55532018-09-15 10:35:08 +0200296```kotlin
Prendota65e6c8c2018-10-17 11:51:08 +0300297import kotlinx.coroutines.*
298
299fun main() = runBlocking {
hadihariri7db55532018-09-15 10:35:08 +0200300 launch { doWorld() }
301 println("Hello,")
302}
303
304// this is your first suspending function
305suspend fun doWorld() {
306 delay(1000L)
307 println("World!")
308}
309```
310
Alexander Prendotacbeef102018-09-27 18:42:04 +0300311</div>
312
Adam Howardf13549a2020-06-02 11:17:46 +0100313> You can get the full code [here](../kotlinx-coroutines-core/jvm/test/guide/example-basic-07.kt).
hadihariri7db55532018-09-15 10:35:08 +0200314
315<!--- TEST
316Hello,
317World!
318-->
319
320
321But what if the extracted function contains a coroutine builder which is invoked on the current scope?
Adam Howardcdbdba92020-06-02 11:21:34 +0100322In this case, the `suspend` modifier on the extracted function is not enough. Making `doWorld` an extension
323method on `CoroutineScope` is one of the solutions, but it may not always be applicable as it does not make the API clearer.
Inego69c26df2019-04-21 14:51:25 +0700324The idiomatic solution is to have either an explicit `CoroutineScope` as a field in a class containing the target function
325or an implicit one when the outer class implements `CoroutineScope`.
Adam Howardcdbdba92020-06-02 11:21:34 +0100326As a last resort, [CoroutineScope(coroutineContext)][CoroutineScope()] can be used, but such an approach is structurally unsafe
Inego69c26df2019-04-21 14:51:25 +0700327because 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 +0200328
329### Coroutines ARE light-weight
330
331Run the following code:
332
Alexander Prendotacbeef102018-09-27 18:42:04 +0300333<div class="sample" markdown="1" theme="idea" data-highlight-only>
334
hadihariri7db55532018-09-15 10:35:08 +0200335```kotlin
Prendota65e6c8c2018-10-17 11:51:08 +0300336import kotlinx.coroutines.*
337
338fun main() = runBlocking {
hadihariri7db55532018-09-15 10:35:08 +0200339 repeat(100_000) { // launch a lot of coroutines
340 launch {
Roman Elizarov57053722020-07-16 19:56:13 +0300341 delay(5000L)
hadihariri7db55532018-09-15 10:35:08 +0200342 print(".")
343 }
344 }
345}
346```
347
Alexander Prendotacbeef102018-09-27 18:42:04 +0300348</div>
349
Adam Howardf13549a2020-06-02 11:17:46 +0100350> You can get the full code [here](../kotlinx-coroutines-core/jvm/test/guide/example-basic-08.kt).
hadihariri7db55532018-09-15 10:35:08 +0200351
352<!--- TEST lines.size == 1 && lines[0] == ".".repeat(100_000) -->
353
Roman Elizarov57053722020-07-16 19:56:13 +0300354It launches 100K coroutines and, after 5 seconds, each coroutine prints a dot.
Adam Howardcdbdba92020-06-02 11:21:34 +0100355
hadihariri7db55532018-09-15 10:35:08 +0200356Now, try that with threads. What would happen? (Most likely your code will produce some sort of out-of-memory error)
357
358### Global coroutines are like daemon threads
359
360The following code launches a long-running coroutine in [GlobalScope] that prints "I'm sleeping" twice a second and then
361returns from the main function after some delay:
362
Prendota65e6c8c2018-10-17 11:51:08 +0300363<div class="sample" markdown="1" theme="idea" data-min-compiler-version="1.3">
Alexander Prendotacbeef102018-09-27 18:42:04 +0300364
hadihariri7db55532018-09-15 10:35:08 +0200365```kotlin
Prendota65e6c8c2018-10-17 11:51:08 +0300366import kotlinx.coroutines.*
367
368fun main() = runBlocking {
369//sampleStart
hadihariri7db55532018-09-15 10:35:08 +0200370 GlobalScope.launch {
371 repeat(1000) { i ->
372 println("I'm sleeping $i ...")
373 delay(500L)
374 }
375 }
376 delay(1300L) // just quit after delay
Prendota65e6c8c2018-10-17 11:51:08 +0300377//sampleEnd
hadihariri7db55532018-09-15 10:35:08 +0200378}
379```
380
Alexander Prendotacbeef102018-09-27 18:42:04 +0300381</div>
382
Adam Howardf13549a2020-06-02 11:17:46 +0100383> You can get the full code [here](../kotlinx-coroutines-core/jvm/test/guide/example-basic-09.kt).
hadihariri7db55532018-09-15 10:35:08 +0200384
385You can run and see that it prints three lines and terminates:
386
387```text
388I'm sleeping 0 ...
389I'm sleeping 1 ...
390I'm sleeping 2 ...
391```
392
393<!--- TEST -->
394
395Active coroutines that were launched in [GlobalScope] do not keep the process alive. They are like daemon threads.
396
Roman Elizarov99c28aa2018-09-23 18:42:36 +0300397<!--- MODULE kotlinx-coroutines-core -->
Roman Elizarov0950dfa2018-07-13 10:33:25 +0300398<!--- INDEX kotlinx.coroutines -->
399[launch]: https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines/launch.html
400[CoroutineScope]: https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines/-coroutine-scope/index.html
401[GlobalScope]: https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines/-global-scope/index.html
402[delay]: https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines/delay.html
403[runBlocking]: https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines/run-blocking.html
404[Job]: https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines/-job/index.html
405[Job.join]: https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines/-job/join.html
Roman Elizaroveb1b5db2020-10-16 10:45:08 +0300406[_coroutineScope]: https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines/coroutine-scope.html
Roman Elizarov0950dfa2018-07-13 10:33:25 +0300407[CoroutineScope()]: https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines/-coroutine-scope.html
Roman Elizarov99c28aa2018-09-23 18:42:36 +0300408<!--- END -->
hadihariri7db55532018-09-15 10:35:08 +0200409
410