blob: 9a0722edab1d053ff1c452c8977939bbae12a92b [file] [log] [blame] [view]
hadihariri7db55532018-09-15 10:35:08 +02001<!--- INCLUDE .*/example-([a-z]+)-([0-9a-z]+)\.kt
2/*
3 * Copyright 2016-2018 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
4 */
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
Roman Elizarov0950dfa2018-07-13 10:33:25 +03009import kotlinx.coroutines.*
hadihariri7db55532018-09-15 10:35:08 +020010-->
11<!--- KNIT ../core/kotlinx-coroutines-core/test/guide/.*\.kt -->
12<!--- TEST_OUT ../core/kotlinx-coroutines-core/test/guide/test/BasicsGuideTest.kt
13// This file was automatically generated from coroutines-guide.md by Knit tool. Do not edit.
Roman Elizarov0950dfa2018-07-13 10:33:25 +030014package kotlinx.coroutines.guide.test
hadihariri7db55532018-09-15 10:35:08 +020015
16import org.junit.Test
17
18class BasicsGuideTest {
19-->
20
21## Table of contents
22
23<!--- TOC -->
24
25* [Coroutine basics](#coroutine-basics)
26 * [Your first coroutine](#your-first-coroutine)
27 * [Bridging blocking and non-blocking worlds](#bridging-blocking-and-non-blocking-worlds)
28 * [Waiting for a job](#waiting-for-a-job)
29 * [Structured concurrency](#structured-concurrency)
30 * [Scope builder](#scope-builder)
31 * [Extract function refactoring](#extract-function-refactoring)
32 * [Coroutines ARE light-weight](#coroutines-are-light-weight)
33 * [Global coroutines are like daemon threads](#global-coroutines-are-like-daemon-threads)
34
35<!--- END_TOC -->
36
37
38## Coroutine basics
39
40This section covers basic coroutine concepts.
41
42### Your first coroutine
43
44Run the following code:
45
Alexander Prendotacbeef102018-09-27 18:42:04 +030046<div class="sample" markdown="1" theme="idea" data-highlight-only>
47
hadihariri7db55532018-09-15 10:35:08 +020048```kotlin
49fun main(args: Array<String>) {
50 GlobalScope.launch { // launch new coroutine in background and continue
51 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
hadihariri7db55532018-09-15 10:35:08 +020061> You can get full code [here](../core/kotlinx-coroutines-core/test/guide/example-basic-01.kt)
62
63Run this code:
64
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
78`GlobalScope.launch { ... }` with `thread { ... }` and `delay(...)` with `Thread.sleep(...)`. Try it.
79
80If you start by replacing `GlobalScope.launch` by `thread`, the compiler produces the following error:
81
82```
83Error: Kotlin: Suspend functions are only allowed to be called from a coroutine or another suspend function
84```
85
86That is because [delay] is a special _suspending function_ that does not block a thread, but _suspends_
87coroutine and it can be only used from a coroutine.
88
89### Bridging blocking and non-blocking worlds
90
91The first example mixes _non-blocking_ `delay(...)` and _blocking_ `Thread.sleep(...)` in the same code.
92It is easy to get lost which one is blocking and which one is not.
93Let's be explicit about blocking using [runBlocking] coroutine builder:
94
Alexander Prendotacbeef102018-09-27 18:42:04 +030095<div class="sample" markdown="1" theme="idea" data-highlight-only>
96
hadihariri7db55532018-09-15 10:35:08 +020097```kotlin
98fun main(args: Array<String>) {
99 GlobalScope.launch { // launch new coroutine in background and continue
100 delay(1000L)
101 println("World!")
102 }
103 println("Hello,") // main thread continues here immediately
104 runBlocking { // but this expression blocks the main thread
105 delay(2000L) // ... while we delay for 2 seconds to keep JVM alive
106 }
107}
108```
109
Alexander Prendotacbeef102018-09-27 18:42:04 +0300110</div>
111
hadihariri7db55532018-09-15 10:35:08 +0200112> You can get full code [here](../core/kotlinx-coroutines-core/test/guide/example-basic-02.kt)
113
114<!--- TEST
115Hello,
116World!
117-->
118
119The result is the same, but this code uses only non-blocking [delay].
120The main thread, that invokes `runBlocking`, _blocks_ until the coroutine inside `runBlocking` completes.
121
122This example can be also rewritten in a more idiomatic way, using `runBlocking` to wrap
123the execution of the main function:
124
Alexander Prendotacbeef102018-09-27 18:42:04 +0300125<div class="sample" markdown="1" theme="idea" data-highlight-only>
126
hadihariri7db55532018-09-15 10:35:08 +0200127```kotlin
Ola Peterssone6b47392018-10-07 16:22:17 +0200128fun main(args: Array<String>) = runBlocking<Unit> { // start main coroutine
hadihariri7db55532018-09-15 10:35:08 +0200129 GlobalScope.launch { // launch new coroutine in background and continue
130 delay(1000L)
131 println("World!")
132 }
133 println("Hello,") // main coroutine continues here immediately
134 delay(2000L) // delaying for 2 seconds to keep JVM alive
135}
136```
137
Alexander Prendotacbeef102018-09-27 18:42:04 +0300138</div>
139
hadihariri7db55532018-09-15 10:35:08 +0200140> You can get full code [here](../core/kotlinx-coroutines-core/test/guide/example-basic-02b.kt)
141
142<!--- TEST
143Hello,
144World!
145-->
146
147Here `runBlocking<Unit> { ... }` works as an adaptor that is used to start the top-level main coroutine.
148We explicitly specify its `Unit` return type, because a well-formed `main` function in Kotlin has to return `Unit`.
149
150This is also a way to write unit-tests for suspending functions:
Alexander Prendotacbeef102018-09-27 18:42:04 +0300151
152<div class="sample" markdown="1" theme="idea" data-highlight-only>
hadihariri7db55532018-09-15 10:35:08 +0200153
154```kotlin
155class MyTest {
156 @Test
157 fun testMySuspendingFunction() = runBlocking<Unit> {
158 // here we can use suspending functions using any assertion style that we like
159 }
160}
161```
162
Alexander Prendotacbeef102018-09-27 18:42:04 +0300163</div>
164
hadihariri7db55532018-09-15 10:35:08 +0200165<!--- CLEAR -->
166
167### Waiting for a job
168
169Delaying for a time while another coroutine is working is not a good approach. Let's explicitly
170wait (in a non-blocking way) until the background [Job] that we have launched is complete:
171
Alexander Prendotacbeef102018-09-27 18:42:04 +0300172<div class="sample" markdown="1" theme="idea" data-highlight-only>
173
hadihariri7db55532018-09-15 10:35:08 +0200174```kotlin
Vsevolod Tolstopyatova2d80882018-09-24 19:51:49 +0300175fun main(args: Array<String>) = runBlocking {
hadihariri7db55532018-09-15 10:35:08 +0200176 val job = GlobalScope.launch { // launch new coroutine and keep a reference to its Job
177 delay(1000L)
178 println("World!")
179 }
180 println("Hello,")
181 job.join() // wait until child coroutine completes
182}
183```
184
Alexander Prendotacbeef102018-09-27 18:42:04 +0300185</div>
186
hadihariri7db55532018-09-15 10:35:08 +0200187> You can get full code [here](../core/kotlinx-coroutines-core/test/guide/example-basic-03.kt)
188
189<!--- TEST
190Hello,
191World!
192-->
193
194Now the result is still the same, but the code of the main coroutine is not tied to the duration of
195the background job in any way. Much better.
196
197### Structured concurrency
198
199There is still something to be desired for practical usage of coroutines.
200When we use `GlobalScope.launch` we create a top-level coroutine. Even though it is light-weight, it still
201consumes some memory resources while it runs. If we forget to keep a reference to the newly launched
202coroutine it still runs. What if the code in the coroutine hangs (for example, we erroneously
203delay for too long), what if we launched too many coroutines and ran out of memory?
204Having to manually keep a reference to all the launched coroutines and [join][Job.join] them is error-prone.
205
206There is a better solution. We can use structured concurrency in our code.
207Instead of launching coroutines in the [GlobalScope], just like we usually do with threads (threads are always global),
208we can launch coroutines in the specific scope of the operation we are performing.
209
210In our example, we have `main` function that is turned into a coroutine using [runBlocking] coroutine builder.
211Every coroutine builder, including `runBlocking`, adds an instance of [CoroutineScope] to the scope its code block.
212We can launch coroutines in this scope without having to `join` them explicitly, because
213an outer coroutine (`runBlocking` in our example) does not complete until all the coroutines launched
214in its scope complete. Thus, we can make our example simpler:
215
Alexander Prendotacbeef102018-09-27 18:42:04 +0300216<div class="sample" markdown="1" theme="idea" data-highlight-only>
217
hadihariri7db55532018-09-15 10:35:08 +0200218```kotlin
Vsevolod Tolstopyatova2d80882018-09-24 19:51:49 +0300219fun main(args: Array<String>) = runBlocking { // this: CoroutineScope
hadihariri7db55532018-09-15 10:35:08 +0200220 launch { // launch new coroutine in the scope of runBlocking
221 delay(1000L)
222 println("World!")
223 }
224 println("Hello,")
225}
226```
227
Alexander Prendotacbeef102018-09-27 18:42:04 +0300228</div>
229
hadihariri7db55532018-09-15 10:35:08 +0200230> You can get full code [here](../core/kotlinx-coroutines-core/test/guide/example-basic-03s.kt)
231
232<!--- TEST
233Hello,
234World!
235-->
236
237### Scope builder
238In addition to the coroutine scope provided by different builders, it is possible to declare your own scope using
239[coroutineScope] builder. It creates new coroutine scope and does not complete until all launched children
240complete. The main difference between [runBlocking] and [coroutineScope] is that the latter does not block the current thread
241while waiting for all children to complete.
242
Alexander Prendotacbeef102018-09-27 18:42:04 +0300243<div class="sample" markdown="1" theme="idea" data-highlight-only>
244
hadihariri7db55532018-09-15 10:35:08 +0200245```kotlin
Vsevolod Tolstopyatova2d80882018-09-24 19:51:49 +0300246fun main(args: Array<String>) = runBlocking { // this: CoroutineScope
hadihariri7db55532018-09-15 10:35:08 +0200247 launch {
248 delay(200L)
249 println("Task from runBlocking")
250 }
251
252 coroutineScope { // Creates a new coroutine scope
253 launch {
254 delay(500L)
255 println("Task from nested launch")
256 }
257
258 delay(100L)
259 println("Task from coroutine scope") // This line will be printed before nested launch
260 }
261
262 println("Coroutine scope is over") // This line is not printed until nested launch completes
263}
264```
265
Alexander Prendotacbeef102018-09-27 18:42:04 +0300266</div>
267
hadihariri7db55532018-09-15 10:35:08 +0200268> You can get full code [here](../core/kotlinx-coroutines-core/test/guide/example-basic-04.kt)
269
270<!--- TEST
271Task from coroutine scope
272Task from runBlocking
273Task from nested launch
274Coroutine scope is over
275-->
276
277### Extract function refactoring
278
279Let's extract the block of code inside `launch { ... }` into a separate function. When you
280perform "Extract function" refactoring on this code you get a new function with `suspend` modifier.
281That is your first _suspending function_. Suspending functions can be used inside coroutines
282just like regular functions, but their additional feature is that they can, in turn,
283use other suspending functions, like `delay` in this example, to _suspend_ execution of a coroutine.
284
Alexander Prendotacbeef102018-09-27 18:42:04 +0300285<div class="sample" markdown="1" theme="idea" data-highlight-only>
286
hadihariri7db55532018-09-15 10:35:08 +0200287```kotlin
Vsevolod Tolstopyatova2d80882018-09-24 19:51:49 +0300288fun main(args: Array<String>) = runBlocking {
hadihariri7db55532018-09-15 10:35:08 +0200289 launch { doWorld() }
290 println("Hello,")
291}
292
293// this is your first suspending function
294suspend fun doWorld() {
295 delay(1000L)
296 println("World!")
297}
298```
299
Alexander Prendotacbeef102018-09-27 18:42:04 +0300300</div>
301
hadihariri7db55532018-09-15 10:35:08 +0200302> You can get full code [here](../core/kotlinx-coroutines-core/test/guide/example-basic-05.kt)
303
304<!--- TEST
305Hello,
306World!
307-->
308
309
310But what if the extracted function contains a coroutine builder which is invoked on the current scope?
311In this case `suspend` modifier on the extracted function is not enough. Making `doWorld` extension
312method on `CoroutineScope` is one of the solutions, but it may not always be applicable as it does not make API clearer.
Vsevolod Tolstopyatovfac516f2018-09-28 14:38:29 +0300313Idiomatic solution is to have either explicit `CoroutineScope` as a field in a class containing target function
314or implicit when outer class implements `CoroutineScope`.
315As a last resort, [CoroutineScope(coroutineContext)][CoroutineScope()] can be used, but such approach is structurally unsafe
316because you no longer have control on the scope this method is executed. Only private API can use this builder.
hadihariri7db55532018-09-15 10:35:08 +0200317
318### Coroutines ARE light-weight
319
320Run the following code:
321
Alexander Prendotacbeef102018-09-27 18:42:04 +0300322<div class="sample" markdown="1" theme="idea" data-highlight-only>
323
hadihariri7db55532018-09-15 10:35:08 +0200324```kotlin
Vsevolod Tolstopyatova2d80882018-09-24 19:51:49 +0300325fun main(args: Array<String>) = runBlocking {
hadihariri7db55532018-09-15 10:35:08 +0200326 repeat(100_000) { // launch a lot of coroutines
327 launch {
328 delay(1000L)
329 print(".")
330 }
331 }
332}
333```
334
Alexander Prendotacbeef102018-09-27 18:42:04 +0300335</div>
336
hadihariri7db55532018-09-15 10:35:08 +0200337> You can get full code [here](../core/kotlinx-coroutines-core/test/guide/example-basic-06.kt)
338
339<!--- TEST lines.size == 1 && lines[0] == ".".repeat(100_000) -->
340
341It launches 100K coroutines and, after a second, each coroutine prints a dot.
342Now, try that with threads. What would happen? (Most likely your code will produce some sort of out-of-memory error)
343
344### Global coroutines are like daemon threads
345
346The following code launches a long-running coroutine in [GlobalScope] that prints "I'm sleeping" twice a second and then
347returns from the main function after some delay:
348
Alexander Prendotacbeef102018-09-27 18:42:04 +0300349<div class="sample" markdown="1" theme="idea" data-highlight-only>
350
hadihariri7db55532018-09-15 10:35:08 +0200351```kotlin
Vsevolod Tolstopyatova2d80882018-09-24 19:51:49 +0300352fun main(args: Array<String>) = runBlocking {
hadihariri7db55532018-09-15 10:35:08 +0200353 GlobalScope.launch {
354 repeat(1000) { i ->
355 println("I'm sleeping $i ...")
356 delay(500L)
357 }
358 }
359 delay(1300L) // just quit after delay
360}
361```
362
Alexander Prendotacbeef102018-09-27 18:42:04 +0300363</div>
364
hadihariri7db55532018-09-15 10:35:08 +0200365> You can get full code [here](../core/kotlinx-coroutines-core/test/guide/example-basic-07.kt)
366
367You can run and see that it prints three lines and terminates:
368
369```text
370I'm sleeping 0 ...
371I'm sleeping 1 ...
372I'm sleeping 2 ...
373```
374
375<!--- TEST -->
376
377Active coroutines that were launched in [GlobalScope] do not keep the process alive. They are like daemon threads.
378
Roman Elizarov99c28aa2018-09-23 18:42:36 +0300379<!--- MODULE kotlinx-coroutines-core -->
Roman Elizarov0950dfa2018-07-13 10:33:25 +0300380<!--- INDEX kotlinx.coroutines -->
381[launch]: https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines/launch.html
382[CoroutineScope]: https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines/-coroutine-scope/index.html
383[GlobalScope]: https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines/-global-scope/index.html
384[delay]: https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines/delay.html
385[runBlocking]: https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines/run-blocking.html
386[Job]: https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines/-job/index.html
387[Job.join]: https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines/-job/join.html
388[coroutineScope]: https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines/coroutine-scope.html
389[CoroutineScope()]: https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines/-coroutine-scope.html
Roman Elizarov99c28aa2018-09-23 18:42:36 +0300390<!--- END -->
hadihariri7db55532018-09-15 10:35:08 +0200391
392