blob: 30c4fdfc49d80bfa9aee33b86af2c6762fba6de5 [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.
7package kotlinx.coroutines.experimental.guide.$$1$$2
8
9import kotlinx.coroutines.experimental.*
10-->
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.
14package kotlinx.coroutines.experimental.guide.test
15
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
46```kotlin
47fun main(args: Array<String>) {
48 GlobalScope.launch { // launch new coroutine in background and continue
49 delay(1000L) // non-blocking delay for 1 second (default time unit is ms)
50 println("World!") // print after delay
51 }
52 println("Hello,") // main thread continues while coroutine is delayed
53 Thread.sleep(2000L) // block main thread for 2 seconds to keep JVM alive
54}
55```
56
57> You can get full code [here](../core/kotlinx-coroutines-core/test/guide/example-basic-01.kt)
58
59Run this code:
60
61```text
62Hello,
63World!
64```
65
66<!--- TEST -->
67
68Essentially, coroutines are light-weight threads.
69They are launched with [launch] _coroutine builder_ in a context of some [CoroutineScope].
70Here we are launching a new coroutine in the [GlobalScope], meaning that the lifetime of the new
71coroutine is limited only by the lifetime of the whole application.
72
73You can achieve the same result replacing
74`GlobalScope.launch { ... }` with `thread { ... }` and `delay(...)` with `Thread.sleep(...)`. Try it.
75
76If you start by replacing `GlobalScope.launch` by `thread`, the compiler produces the following error:
77
78```
79Error: Kotlin: Suspend functions are only allowed to be called from a coroutine or another suspend function
80```
81
82That is because [delay] is a special _suspending function_ that does not block a thread, but _suspends_
83coroutine and it can be only used from a coroutine.
84
85### Bridging blocking and non-blocking worlds
86
87The first example mixes _non-blocking_ `delay(...)` and _blocking_ `Thread.sleep(...)` in the same code.
88It is easy to get lost which one is blocking and which one is not.
89Let's be explicit about blocking using [runBlocking] coroutine builder:
90
91```kotlin
92fun main(args: Array<String>) {
93 GlobalScope.launch { // launch new coroutine in background and continue
94 delay(1000L)
95 println("World!")
96 }
97 println("Hello,") // main thread continues here immediately
98 runBlocking { // but this expression blocks the main thread
99 delay(2000L) // ... while we delay for 2 seconds to keep JVM alive
100 }
101}
102```
103
104> You can get full code [here](../core/kotlinx-coroutines-core/test/guide/example-basic-02.kt)
105
106<!--- TEST
107Hello,
108World!
109-->
110
111The result is the same, but this code uses only non-blocking [delay].
112The main thread, that invokes `runBlocking`, _blocks_ until the coroutine inside `runBlocking` completes.
113
114This example can be also rewritten in a more idiomatic way, using `runBlocking` to wrap
115the execution of the main function:
116
117```kotlin
118fun main(args: Array<String>) = runBlocking<Unit> { // start main coroutine
119 GlobalScope.launch { // launch new coroutine in background and continue
120 delay(1000L)
121 println("World!")
122 }
123 println("Hello,") // main coroutine continues here immediately
124 delay(2000L) // delaying for 2 seconds to keep JVM alive
125}
126```
127
128> You can get full code [here](../core/kotlinx-coroutines-core/test/guide/example-basic-02b.kt)
129
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
138This is also a way to write unit-tests for suspending functions:
139
140```kotlin
141class MyTest {
142 @Test
143 fun testMySuspendingFunction() = runBlocking<Unit> {
144 // here we can use suspending functions using any assertion style that we like
145 }
146}
147```
148
149<!--- CLEAR -->
150
151### Waiting for a job
152
153Delaying for a time while another coroutine is working is not a good approach. Let's explicitly
154wait (in a non-blocking way) until the background [Job] that we have launched is complete:
155
156```kotlin
157fun main(args: Array<String>) = runBlocking<Unit> {
158 val job = GlobalScope.launch { // launch new coroutine and keep a reference to its Job
159 delay(1000L)
160 println("World!")
161 }
162 println("Hello,")
163 job.join() // wait until child coroutine completes
164}
165```
166
167> You can get full code [here](../core/kotlinx-coroutines-core/test/guide/example-basic-03.kt)
168
169<!--- TEST
170Hello,
171World!
172-->
173
174Now the result is still the same, but the code of the main coroutine is not tied to the duration of
175the background job in any way. Much better.
176
177### Structured concurrency
178
179There is still something to be desired for practical usage of coroutines.
180When we use `GlobalScope.launch` we create a top-level coroutine. Even though it is light-weight, it still
181consumes some memory resources while it runs. If we forget to keep a reference to the newly launched
182coroutine it still runs. What if the code in the coroutine hangs (for example, we erroneously
183delay for too long), what if we launched too many coroutines and ran out of memory?
184Having to manually keep a reference to all the launched coroutines and [join][Job.join] them is error-prone.
185
186There is a better solution. We can use structured concurrency in our code.
187Instead of launching coroutines in the [GlobalScope], just like we usually do with threads (threads are always global),
188we can launch coroutines in the specific scope of the operation we are performing.
189
190In our example, we have `main` function that is turned into a coroutine using [runBlocking] coroutine builder.
191Every coroutine builder, including `runBlocking`, adds an instance of [CoroutineScope] to the scope its code block.
192We can launch coroutines in this scope without having to `join` them explicitly, because
193an outer coroutine (`runBlocking` in our example) does not complete until all the coroutines launched
194in its scope complete. Thus, we can make our example simpler:
195
196```kotlin
197fun main(args: Array<String>) = runBlocking<Unit> { // this: CoroutineScope
198 launch { // launch new coroutine in the scope of runBlocking
199 delay(1000L)
200 println("World!")
201 }
202 println("Hello,")
203}
204```
205
206> You can get full code [here](../core/kotlinx-coroutines-core/test/guide/example-basic-03s.kt)
207
208<!--- TEST
209Hello,
210World!
211-->
212
213### Scope builder
214In addition to the coroutine scope provided by different builders, it is possible to declare your own scope using
215[coroutineScope] builder. It creates new coroutine scope and does not complete until all launched children
216complete. The main difference between [runBlocking] and [coroutineScope] is that the latter does not block the current thread
217while waiting for all children to complete.
218
219```kotlin
220fun main(args: Array<String>) = runBlocking<Unit> { // this: CoroutineScope
221 launch {
222 delay(200L)
223 println("Task from runBlocking")
224 }
225
226 coroutineScope { // Creates a new coroutine scope
227 launch {
228 delay(500L)
229 println("Task from nested launch")
230 }
231
232 delay(100L)
233 println("Task from coroutine scope") // This line will be printed before nested launch
234 }
235
236 println("Coroutine scope is over") // This line is not printed until nested launch completes
237}
238```
239
240> You can get full code [here](../core/kotlinx-coroutines-core/test/guide/example-basic-04.kt)
241
242<!--- TEST
243Task from coroutine scope
244Task from runBlocking
245Task from nested launch
246Coroutine scope is over
247-->
248
249### Extract function refactoring
250
251Let's extract the block of code inside `launch { ... }` into a separate function. When you
252perform "Extract function" refactoring on this code you get a new function with `suspend` modifier.
253That is your first _suspending function_. Suspending functions can be used inside coroutines
254just like regular functions, but their additional feature is that they can, in turn,
255use other suspending functions, like `delay` in this example, to _suspend_ execution of a coroutine.
256
257```kotlin
258fun main(args: Array<String>) = runBlocking<Unit> {
259 launch { doWorld() }
260 println("Hello,")
261}
262
263// this is your first suspending function
264suspend fun doWorld() {
265 delay(1000L)
266 println("World!")
267}
268```
269
270> You can get full code [here](../core/kotlinx-coroutines-core/test/guide/example-basic-05.kt)
271
272<!--- TEST
273Hello,
274World!
275-->
276
277
278But what if the extracted function contains a coroutine builder which is invoked on the current scope?
279In this case `suspend` modifier on the extracted function is not enough. Making `doWorld` extension
280method on `CoroutineScope` is one of the solutions, but it may not always be applicable as it does not make API clearer.
281[currentScope] builder comes to help: it inherits current [CoroutineScope] from the coroutine context it is invoked.
282
283```kotlin
284fun main(args: Array<String>) = runBlocking<Unit> {
285 launchDoWorld()
286 println("Hello,")
287}
288
289// this is your first suspending function
290suspend fun launchDoWorld() = currentScope {
291 launch {
292 println("World!")
293 }
294}
295```
296
297> You can get full code [here](../core/kotlinx-coroutines-core/test/guide/example-basic-05s.kt)
298
299<!--- TEST
300Hello,
301World!
302-->
303
304### Coroutines ARE light-weight
305
306Run the following code:
307
308```kotlin
309fun main(args: Array<String>) = runBlocking<Unit> {
310 repeat(100_000) { // launch a lot of coroutines
311 launch {
312 delay(1000L)
313 print(".")
314 }
315 }
316}
317```
318
319> You can get full code [here](../core/kotlinx-coroutines-core/test/guide/example-basic-06.kt)
320
321<!--- TEST lines.size == 1 && lines[0] == ".".repeat(100_000) -->
322
323It launches 100K coroutines and, after a second, each coroutine prints a dot.
324Now, try that with threads. What would happen? (Most likely your code will produce some sort of out-of-memory error)
325
326### Global coroutines are like daemon threads
327
328The following code launches a long-running coroutine in [GlobalScope] that prints "I'm sleeping" twice a second and then
329returns from the main function after some delay:
330
331```kotlin
332fun main(args: Array<String>) = runBlocking<Unit> {
333 GlobalScope.launch {
334 repeat(1000) { i ->
335 println("I'm sleeping $i ...")
336 delay(500L)
337 }
338 }
339 delay(1300L) // just quit after delay
340}
341```
342
343> You can get full code [here](../core/kotlinx-coroutines-core/test/guide/example-basic-07.kt)
344
345You can run and see that it prints three lines and terminates:
346
347```text
348I'm sleeping 0 ...
349I'm sleeping 1 ...
350I'm sleeping 2 ...
351```
352
353<!--- TEST -->
354
355Active coroutines that were launched in [GlobalScope] do not keep the process alive. They are like daemon threads.
356
Roman Elizarov99c28aa2018-09-23 18:42:36 +0300357<!--- MODULE kotlinx-coroutines-core -->
358<!--- INDEX kotlinx.coroutines.experimental -->
359[launch]: https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines.experimental/launch.html
360[CoroutineScope]: https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines.experimental/-coroutine-scope/index.html
361[GlobalScope]: https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines.experimental/-global-scope/index.html
362[delay]: https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines.experimental/delay.html
363[runBlocking]: https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines.experimental/run-blocking.html
364[Job]: https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines.experimental/-job/index.html
365[Job.join]: https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines.experimental/-job/join.html
366[coroutineScope]: https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines.experimental/coroutine-scope.html
367[currentScope]: https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines.experimental/current-scope.html
368<!--- END -->
hadihariri7db55532018-09-15 10:35:08 +0200369
370