blob: ff6f6a58706bbdd43dd24a06a3ab3bc0589e94ae [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
60You can achieve the same result replacing
Vsevolod Tolstopyatov445e0262019-11-25 18:56:24 +030061`GlobalScope.launch { ... }` with `thread { ... }` and `delay(...)` with `Thread.sleep(...)`.
62Try it (don't forget to import `kotlin.concurrent.thread`).
hadihariri7db55532018-09-15 10:35:08 +020063
64If you start by replacing `GlobalScope.launch` by `thread`, the compiler produces the following error:
65
66```
67Error: Kotlin: Suspend functions are only allowed to be called from a coroutine or another suspend function
68```
69
70That is because [delay] is a special _suspending function_ that does not block a thread, but _suspends_
71coroutine and it can be only used from a coroutine.
72
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.
hadihariri7db55532018-09-15 10:35:08 +020077Let's be explicit about blocking using [runBlocking] coroutine builder:
78
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
198coroutine it still runs. What if the code in the coroutine hangs (for example, we erroneously
199delay 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
206In our example, we have `main` function that is turned into a coroutine using [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
236In addition to the coroutine scope provided by different builders, it is possible to declare your own scope using
Inego6da0ccd2019-04-21 14:26:40 +0700237[coroutineScope] builder. It creates a coroutine scope and does not complete until all launched children
Vsevolod Tolstopyatove303e6b2019-10-09 13:55:57 +0300238complete.
239
240[runBlocking] and [coroutineScope] may look similar because they both wait for its body and all its children to complete.
241The main difference between these two is that the [runBlocking] method _blocks_ the current thread for waiting,
242while [coroutineScope] just suspends, releasing the underlying thread for other usages.
243Because of that difference, [runBlocking] is a regular function and [coroutineScope] is a suspending function.
244
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
Vsevolod Tolstopyatove303e6b2019-10-09 13:55:57 +0300283Note that right after "Task from coroutine scope" message, while waiting for nested launch,
284 "Task from runBlocking" is executed and printed, though coroutineScope is not completed yet.
285
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
289perform "Extract function" refactoring on this code you get a new function with `suspend` modifier.
290That is your first _suspending function_. Suspending functions can be used inside coroutines
291just like regular functions, but their additional feature is that they can, in turn,
292use other suspending functions, like `delay` in this example, to _suspend_ execution of a coroutine.
293
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?
Petter Måhlén61302382019-07-02 08:01:36 +0200322In this case `suspend` modifier on the extracted function is not enough. Making `doWorld` an extension
hadihariri7db55532018-09-15 10:35:08 +0200323method 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 +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`.
Vsevolod Tolstopyatovfac516f2018-09-28 14:38:29 +0300326As a last resort, [CoroutineScope(coroutineContext)][CoroutineScope()] can be used, but such 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 {
341 delay(1000L)
342 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
354It launches 100K coroutines and, after a second, each coroutine prints a dot.
355Now, try that with threads. What would happen? (Most likely your code will produce some sort of out-of-memory error)
356
357### Global coroutines are like daemon threads
358
359The following code launches a long-running coroutine in [GlobalScope] that prints "I'm sleeping" twice a second and then
360returns from the main function after some delay:
361
Prendota65e6c8c2018-10-17 11:51:08 +0300362<div class="sample" markdown="1" theme="idea" data-min-compiler-version="1.3">
Alexander Prendotacbeef102018-09-27 18:42:04 +0300363
hadihariri7db55532018-09-15 10:35:08 +0200364```kotlin
Prendota65e6c8c2018-10-17 11:51:08 +0300365import kotlinx.coroutines.*
366
367fun main() = runBlocking {
368//sampleStart
hadihariri7db55532018-09-15 10:35:08 +0200369 GlobalScope.launch {
370 repeat(1000) { i ->
371 println("I'm sleeping $i ...")
372 delay(500L)
373 }
374 }
375 delay(1300L) // just quit after delay
Prendota65e6c8c2018-10-17 11:51:08 +0300376//sampleEnd
hadihariri7db55532018-09-15 10:35:08 +0200377}
378```
379
Alexander Prendotacbeef102018-09-27 18:42:04 +0300380</div>
381
Adam Howardf13549a2020-06-02 11:17:46 +0100382> You can get the full code [here](../kotlinx-coroutines-core/jvm/test/guide/example-basic-09.kt).
hadihariri7db55532018-09-15 10:35:08 +0200383
384You can run and see that it prints three lines and terminates:
385
386```text
387I'm sleeping 0 ...
388I'm sleeping 1 ...
389I'm sleeping 2 ...
390```
391
392<!--- TEST -->
393
394Active coroutines that were launched in [GlobalScope] do not keep the process alive. They are like daemon threads.
395
Roman Elizarov99c28aa2018-09-23 18:42:36 +0300396<!--- MODULE kotlinx-coroutines-core -->
Roman Elizarov0950dfa2018-07-13 10:33:25 +0300397<!--- INDEX kotlinx.coroutines -->
398[launch]: https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines/launch.html
399[CoroutineScope]: https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines/-coroutine-scope/index.html
400[GlobalScope]: https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines/-global-scope/index.html
401[delay]: https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines/delay.html
402[runBlocking]: https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines/run-blocking.html
403[Job]: https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines/-job/index.html
404[Job.join]: https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines/-job/join.html
405[coroutineScope]: https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines/coroutine-scope.html
406[CoroutineScope()]: https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines/-coroutine-scope.html
Roman Elizarov99c28aa2018-09-23 18:42:36 +0300407<!--- END -->
hadihariri7db55532018-09-15 10:35:08 +0200408
409