1<!--- INCLUDE .*/example-([a-z]+)-([0-9a-z]+)\.kt 2/* 3 * Copyright 2016-2019 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.guide.$$1$$2 8--> 9<!--- KNIT ../kotlinx-coroutines-core/jvm/test/guide/.*\.kt --> 10<!--- TEST_OUT ../kotlinx-coroutines-core/jvm/test/guide/test/BasicsGuideTest.kt 11// This file was automatically generated from coroutines-guide.md by Knit tool. Do not edit. 12package kotlinx.coroutines.guide.test 13 14import org.junit.Test 15 16class BasicsGuideTest { 17--> 18 19**Table of contents** 20 21<!--- TOC --> 22 23* [Coroutine Basics](#coroutine-basics) 24 * [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 36## Coroutine Basics 37 38This section covers basic coroutine concepts. 39 40### Your first coroutine 41 42Run the following code: 43 44<div class="sample" markdown="1" theme="idea" data-min-compiler-version="1.3"> 45 46```kotlin 47import kotlinx.coroutines.* 48 49fun main() { 50 GlobalScope.launch { // launch a 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 59</div> 60 61> You can get full code [here](../kotlinx-coroutines-core/jvm/test/guide/example-basic-01.kt). 62 63You will see the following result: 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 lose track of which one is blocking and which one is not. 93Let's be explicit about blocking using [runBlocking] coroutine builder: 94 95<div class="sample" markdown="1" theme="idea" data-min-compiler-version="1.3"> 96 97```kotlin 98import kotlinx.coroutines.* 99 100fun main() { 101 GlobalScope.launch { // launch a new coroutine in background and continue 102 delay(1000L) 103 println("World!") 104 } 105 println("Hello,") // main thread continues here immediately 106 runBlocking { // but this expression blocks the main thread 107 delay(2000L) // ... while we delay for 2 seconds to keep JVM alive 108 } 109} 110``` 111 112</div> 113 114> You can get full code [here](../kotlinx-coroutines-core/jvm/test/guide/example-basic-02.kt). 115 116<!--- TEST 117Hello, 118World! 119--> 120 121The result is the same, but this code uses only non-blocking [delay]. 122The main thread invoking `runBlocking` _blocks_ until the coroutine inside `runBlocking` completes. 123 124This example can be also rewritten in a more idiomatic way, using `runBlocking` to wrap 125the execution of the main function: 126 127<div class="sample" markdown="1" theme="idea" data-min-compiler-version="1.3"> 128 129```kotlin 130import kotlinx.coroutines.* 131 132fun main() = runBlocking<Unit> { // start main coroutine 133 GlobalScope.launch { // launch a new coroutine in background and continue 134 delay(1000L) 135 println("World!") 136 } 137 println("Hello,") // main coroutine continues here immediately 138 delay(2000L) // delaying for 2 seconds to keep JVM alive 139} 140``` 141 142</div> 143 144> You can get full code [here](../kotlinx-coroutines-core/jvm/test/guide/example-basic-02b.kt). 145 146<!--- TEST 147Hello, 148World! 149--> 150 151Here `runBlocking<Unit> { ... }` works as an adaptor that is used to start the top-level main coroutine. 152We explicitly specify its `Unit` return type, because a well-formed `main` function in Kotlin has to return `Unit`. 153 154This is also a way to write unit tests for suspending functions: 155 156<!--- INCLUDE 157import kotlinx.coroutines.* 158--> 159 160<div class="sample" markdown="1" theme="idea" data-highlight-only> 161 162```kotlin 163class MyTest { 164 @Test 165 fun testMySuspendingFunction() = runBlocking<Unit> { 166 // here we can use suspending functions using any assertion style that we like 167 } 168} 169``` 170 171</div> 172 173<!--- CLEAR --> 174 175### Waiting for a job 176 177Delaying for a time while another coroutine is working is not a good approach. Let's explicitly 178wait (in a non-blocking way) until the background [Job] that we have launched is complete: 179 180<div class="sample" markdown="1" theme="idea" data-min-compiler-version="1.3"> 181 182```kotlin 183import kotlinx.coroutines.* 184 185fun main() = runBlocking { 186//sampleStart 187 val job = GlobalScope.launch { // launch a new coroutine and keep a reference to its Job 188 delay(1000L) 189 println("World!") 190 } 191 println("Hello,") 192 job.join() // wait until child coroutine completes 193//sampleEnd 194} 195``` 196 197</div> 198 199> You can get full code [here](../kotlinx-coroutines-core/jvm/test/guide/example-basic-03.kt). 200 201<!--- TEST 202Hello, 203World! 204--> 205 206Now the result is still the same, but the code of the main coroutine is not tied to the duration of 207the background job in any way. Much better. 208 209### Structured concurrency 210 211There is still something to be desired for practical usage of coroutines. 212When we use `GlobalScope.launch`, we create a top-level coroutine. Even though it is light-weight, it still 213consumes some memory resources while it runs. If we forget to keep a reference to the newly launched 214coroutine it still runs. What if the code in the coroutine hangs (for example, we erroneously 215delay for too long), what if we launched too many coroutines and ran out of memory? 216Having to manually keep references to all the launched coroutines and [join][Job.join] them is error-prone. 217 218There is a better solution. We can use structured concurrency in our code. 219Instead of launching coroutines in the [GlobalScope], just like we usually do with threads (threads are always global), 220we can launch coroutines in the specific scope of the operation we are performing. 221 222In our example, we have `main` function that is turned into a coroutine using [runBlocking] coroutine builder. 223Every coroutine builder, including `runBlocking`, adds an instance of [CoroutineScope] to the scope of its code block. 224We can launch coroutines in this scope without having to `join` them explicitly, because 225an outer coroutine (`runBlocking` in our example) does not complete until all the coroutines launched 226in its scope complete. Thus, we can make our example simpler: 227 228<div class="sample" markdown="1" theme="idea" data-min-compiler-version="1.3"> 229 230```kotlin 231import kotlinx.coroutines.* 232 233fun main() = runBlocking { // this: CoroutineScope 234 launch { // launch a new coroutine in the scope of runBlocking 235 delay(1000L) 236 println("World!") 237 } 238 println("Hello,") 239} 240``` 241 242</div> 243 244> You can get full code [here](../kotlinx-coroutines-core/jvm/test/guide/example-basic-03s.kt). 245 246<!--- TEST 247Hello, 248World! 249--> 250 251### Scope builder 252In addition to the coroutine scope provided by different builders, it is possible to declare your own scope using 253[coroutineScope] builder. It creates a coroutine scope and does not complete until all launched children 254complete. The main difference between [runBlocking] and [coroutineScope] is that the latter does not block the current thread 255while waiting for all children to complete. 256 257<div class="sample" markdown="1" theme="idea" data-min-compiler-version="1.3"> 258 259```kotlin 260import kotlinx.coroutines.* 261 262fun main() = runBlocking { // this: CoroutineScope 263 launch { 264 delay(200L) 265 println("Task from runBlocking") 266 } 267 268 coroutineScope { // Creates a coroutine scope 269 launch { 270 delay(500L) 271 println("Task from nested launch") 272 } 273 274 delay(100L) 275 println("Task from coroutine scope") // This line will be printed before the nested launch 276 } 277 278 println("Coroutine scope is over") // This line is not printed until the nested launch completes 279} 280``` 281 282</div> 283 284> You can get full code [here](../kotlinx-coroutines-core/jvm/test/guide/example-basic-04.kt). 285 286<!--- TEST 287Task from coroutine scope 288Task from runBlocking 289Task from nested launch 290Coroutine scope is over 291--> 292 293### Extract function refactoring 294 295Let's extract the block of code inside `launch { ... }` into a separate function. When you 296perform "Extract function" refactoring on this code you get a new function with `suspend` modifier. 297That is your first _suspending function_. Suspending functions can be used inside coroutines 298just like regular functions, but their additional feature is that they can, in turn, 299use other suspending functions, like `delay` in this example, to _suspend_ execution of a coroutine. 300 301<div class="sample" markdown="1" theme="idea" data-min-compiler-version="1.3"> 302 303```kotlin 304import kotlinx.coroutines.* 305 306fun main() = runBlocking { 307 launch { doWorld() } 308 println("Hello,") 309} 310 311// this is your first suspending function 312suspend fun doWorld() { 313 delay(1000L) 314 println("World!") 315} 316``` 317 318</div> 319 320> You can get full code [here](../kotlinx-coroutines-core/jvm/test/guide/example-basic-05.kt). 321 322<!--- TEST 323Hello, 324World! 325--> 326 327 328But what if the extracted function contains a coroutine builder which is invoked on the current scope? 329In this case `suspend` modifier on the extracted function is not enough. Making `doWorld` an extension 330method on `CoroutineScope` is one of the solutions, but it may not always be applicable as it does not make API clearer. 331The idiomatic solution is to have either an explicit `CoroutineScope` as a field in a class containing the target function 332or an implicit one when the outer class implements `CoroutineScope`. 333As a last resort, [CoroutineScope(coroutineContext)][CoroutineScope()] can be used, but such approach is structurally unsafe 334because you no longer have control on the scope of execution of this method. Only private APIs can use this builder. 335 336### Coroutines ARE light-weight 337 338Run the following code: 339 340<div class="sample" markdown="1" theme="idea" data-highlight-only> 341 342```kotlin 343import kotlinx.coroutines.* 344 345fun main() = runBlocking { 346 repeat(100_000) { // launch a lot of coroutines 347 launch { 348 delay(1000L) 349 print(".") 350 } 351 } 352} 353``` 354 355</div> 356 357> You can get full code [here](../kotlinx-coroutines-core/jvm/test/guide/example-basic-06.kt). 358 359<!--- TEST lines.size == 1 && lines[0] == ".".repeat(100_000) --> 360 361It launches 100K coroutines and, after a second, each coroutine prints a dot. 362Now, try that with threads. What would happen? (Most likely your code will produce some sort of out-of-memory error) 363 364### Global coroutines are like daemon threads 365 366The following code launches a long-running coroutine in [GlobalScope] that prints "I'm sleeping" twice a second and then 367returns from the main function after some delay: 368 369<div class="sample" markdown="1" theme="idea" data-min-compiler-version="1.3"> 370 371```kotlin 372import kotlinx.coroutines.* 373 374fun main() = runBlocking { 375//sampleStart 376 GlobalScope.launch { 377 repeat(1000) { i -> 378 println("I'm sleeping $i ...") 379 delay(500L) 380 } 381 } 382 delay(1300L) // just quit after delay 383//sampleEnd 384} 385``` 386 387</div> 388 389> You can get full code [here](../kotlinx-coroutines-core/jvm/test/guide/example-basic-07.kt). 390 391You can run and see that it prints three lines and terminates: 392 393```text 394I'm sleeping 0 ... 395I'm sleeping 1 ... 396I'm sleeping 2 ... 397``` 398 399<!--- TEST --> 400 401Active coroutines that were launched in [GlobalScope] do not keep the process alive. They are like daemon threads. 402 403<!--- MODULE kotlinx-coroutines-core --> 404<!--- INDEX kotlinx.coroutines --> 405[launch]: https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines/launch.html 406[CoroutineScope]: https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines/-coroutine-scope/index.html 407[GlobalScope]: https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines/-global-scope/index.html 408[delay]: https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines/delay.html 409[runBlocking]: https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines/run-blocking.html 410[Job]: https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines/-job/index.html 411[Job.join]: https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines/-job/join.html 412[coroutineScope]: https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines/coroutine-scope.html 413[CoroutineScope()]: https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines/-coroutine-scope.html 414<!--- END --> 415 416 417