aboutsummaryrefslogtreecommitdiff
path: root/docs/topics/coroutines-basic-jvm.md
diff options
context:
space:
mode:
Diffstat (limited to 'docs/topics/coroutines-basic-jvm.md')
-rw-r--r--docs/topics/coroutines-basic-jvm.md267
1 files changed, 0 insertions, 267 deletions
diff --git a/docs/topics/coroutines-basic-jvm.md b/docs/topics/coroutines-basic-jvm.md
deleted file mode 100644
index 3b067ea8..00000000
--- a/docs/topics/coroutines-basic-jvm.md
+++ /dev/null
@@ -1,267 +0,0 @@
-[//]: # (title: Create a basic coroutine – tutorial)
-
-Kotlin 1.1 introduced coroutines, a new way of writing asynchronous, non-blocking code (and much more). In this tutorial you will go through some basics of using Kotlin coroutines with the help of the `kotlinx.coroutines` library, which is a collection of helpers and wrappers for existing Java libraries.
-
-## Set up a project
-
-### Gradle
-
-In IntelliJ IDEA go to **File** \| **New** \| **Project**.:
-
-![Create a new project](new-gradle-project-jvm.png)
-
-Then follow the wizard steps. You'll have a `build.gradle` file created with Kotlin configured according to [this document](gradle.md).
-Make sure it's configured for Kotlin 1.3 or higher.
-
-Since we'll be using the [`kotlinx.coroutines`](https://github.com/Kotlin/kotlinx.coroutines), let's add its recent version to our dependencies:
-
-<tabs>
-
-```groovy
-dependencies {
- ...
- implementation 'org.jetbrains.kotlinx:kotlinx-coroutines-core:%coroutinesVersion%'
-}
-```
-
-```kotlin
-dependencies {
- ...
- implementation("org.jetbrains.kotlinx:kotlinx-coroutines-core:%coroutinesVersion%")
-}
-```
-</tabs>
-
-This library is published to the [Maven Central repository](https://search.maven.org/artifact/org.jetbrains.kotlinx/kotlinx-coroutines-core), so add the following:
-
-```groovy
-repositories {
- mavenCentral()
-}
-```
-
-That's it, we are good to go and write code under `src/main/kotlin`.
-
-### Maven
-
-In IntelliJ IDEA go to **File** \| **New** \| **Project** and check the **Create from archetype** box:
-
-![Create a new project](new-mvn-project-jvm.png)
-
-Then follow the wizard steps. You'll have a `pom.xml` file created with Kotlin configured according to [this document](maven.md).
-Make sure it's configured for Kotlin 1.3 or higher.
-
-```xml
-<plugin>
- <groupId>org.jetbrains.kotlin</groupId>
- <artifactId>kotlin-maven-plugin</artifactId>
- ...
- <configuration>
- <args>
- <arg>-Xcoroutines=enable</arg>
- </args>
- </configuration>
-</plugin>
-```
-
-Since we'll be using the [`kotlinx.coroutines`](https://github.com/Kotlin/kotlinx.coroutines), let's add its recent version to our dependencies:
-
-```xml
-<dependencies>
- ...
- <dependency>
- <groupId>org.jetbrains.kotlinx</groupId>
- <artifactId>kotlinx-coroutines-core</artifactId>
- <version>%coroutinesVersion%</version>
- </dependency>
-</dependencies>
-```
-
-This library is published to the [Maven Central repository](https://search.maven.org/artifact/org.jetbrains.kotlinx/kotlinx-coroutines-core), which Maven will download from by default.
-
-That's it, we are good to go and write code under `src/main/kotlin`.
-
-## My first coroutine
-
-One can think of a coroutine as a light-weight thread. Like threads, coroutines can run in parallel, wait for each other and communicate.
-The biggest difference is that coroutines are very cheap, almost free: we can create thousands of them, and pay very little in terms of performance.
-True threads, on the other hand, are expensive to start and keep around. A thousand threads can be a serious challenge for a modern machine.
-
-So, how do we start a coroutine? Let's use the `launch {}` function:
-
-```kotlin
-launch {
- ...
-}
-```
-
-This starts a new coroutine. By default, coroutines are run on a shared pool of threads.
-Threads still exist in a program based on coroutines, but one thread can run many coroutines, so there's no need for
-too many threads.
-
-Let's look at a full program that uses `launch`:
-
-```kotlin
-import kotlinx.coroutines.*
-
-fun main(args: Array<String>) {
-//sampleStart
- println("Start")
-
- // Start a coroutine
- GlobalScope.launch {
- delay(1000)
- println("Hello")
- }
-
- Thread.sleep(2000) // wait for 2 seconds
- println("Stop")
-//sampleEnd
-}
-```
-{kotlin-runnable="true" kotlin-min-compiler-version="1.3"}
-
-Here we start a coroutine that waits for 1 second and prints `Hello`.
-
-We are using the `delay()` function that's like `Thread.sleep()`, but better: it _doesn't block a thread_, but only suspends the coroutine itself.
-The thread is returned to the pool while the coroutine is waiting, and when the waiting is done, the coroutine resumes on a free thread in the pool.
-
-The main thread (that runs the `main()` function) must wait until our coroutine completes, otherwise the program ends before `Hello` is printed.
-
-_Exercise: try removing the `sleep()` from the program above and see the result._
-
- If we try to use the same non-blocking `delay()` function directly inside `main()`, we'll get a compiler error:
-
-> Suspend functions are only allowed to be called from a coroutine or another suspend function.
->
-{type="note"}
-
-This is because we are not inside any coroutine. We can use delay if we wrap it into `runBlocking {}` that starts a coroutine and waits until it's done:
-
-```kotlin
-runBlocking {
- delay(2000)
-}
-```
-
-So, first the resulting program prints `Start`, then it runs a coroutine through `launch {}`, then it runs another one through `runBlocking {}` and blocks until it's done, then prints `Stop`. Meanwhile the first coroutine completes and prints `Hello`. Just like threads, we told you :)
-
-## Let's run a lot of them
-
-Now, let's make sure that coroutines are really cheaper than threads. How about starting a million of them? Let's try starting a million threads first:
-
-```kotlin
-val c = AtomicLong()
-
-for (i in 1..1_000_000L)
- thread(start = true) {
- c.addAndGet(i)
- }
-
-println(c.get())
-```
-
-This runs a 1'000'000 threads each of which adds to a common counter. My patience runs out before this program completes on my machine (definitely over a minute).
-
-Let's try the same with coroutines:
-
-```kotlin
-val c = AtomicLong()
-
-for (i in 1..1_000_000L)
- GlobalScope.launch {
- c.addAndGet(i)
- }
-
-println(c.get())
-```
-
-This example completes in less than a second for me, but it prints some arbitrary number, because some coroutines don't finish before `main()` prints the result. Let's fix that.
-
-We could use the same means of synchronization that are applicable to threads (a `CountDownLatch` is what crosses my mind in this case), but let's take a safer and cleaner path.
-
-## Async: returning a value from a coroutine
-
-Another way of starting a coroutine is `async {}`. It is like `launch {}`, but returns an instance of `Deferred<T>`, which has an `await()` function that returns the result of the coroutine. `Deferred<T>` is a very basic [future](https://en.wikipedia.org/wiki/Futures_and_promises) (fully-fledged JDK futures are also supported, but here we'll confine ourselves to `Deferred` for now).
-
-Let's create a million coroutines again, keeping their `Deferred` objects. Now there's no need in the atomic counter, as we can just return the numbers to be added from our coroutines:
-
-```kotlin
-val deferred = (1..1_000_000).map { n ->
- GlobalScope.async {
- n
- }
-}
-```
-
-All these have already started, all we need is collect the results:
-
-```kotlin
-val sum = deferred.sumOf { it.await().toLong() }
-```
-
-We simply take every coroutine and await its result here, then all results are added together by the standard library function `sumOf()`. But the compiler rightfully complains:
-
-> Suspend functions are only allowed to be called from a coroutine or another suspend function.
->
-{type="note"}
-
-`await()` can not be called outside a coroutine, because it needs to suspend until the computation finishes, and only coroutines can suspend in a non-blocking way. So, let's put this inside a coroutine:
-
-```kotlin
-runBlocking {
- val sum = deferred.sumOf { it.await().toLong() }
- println("Sum: $sum")
-}
-```
-
-Now it prints something sensible: `500000500000`, because all coroutines complete.
-
-Let's also make sure that our coroutines actually run in parallel. If we add a 1-second `delay()` to each of the `async`'s, the resulting program won't run for 1'000'000 seconds (over 11,5 days):
-
-```kotlin
-val deferred = (1..1_000_000).map { n ->
- GlobalScope.async {
- delay(1000)
- n
- }
-}
-```
-
-This takes about 10 seconds on my machine, so yes, coroutines do run in parallel.
-
-## Suspending functions
-
-Now, let's say we want to extract our _workload_ (which is "wait 1 second and return a number") into a separate function:
-
-```kotlin
-fun workload(n: Int): Int {
- delay(1000)
- return n
-}
-```
-
-A familiar error pops up:
-
-> Suspend functions are only allowed to be called from a coroutine or another suspend function.
->
-{type="note"}
-
-Let's dig a little into what it means. The biggest merit of coroutines is that they can _suspend_ without blocking a thread. The compiler has to emit some special code to make this possible, so we have to mark functions that _may suspend_ explicitly in the code. We use the `suspend` modifier for it:
-
-```kotlin
-suspend fun workload(n: Int): Int {
- delay(1000)
- return n
-}
-```
-
-Now when we call `workload()` from a coroutine, the compiler knows that it may suspend and will prepare accordingly:
-
-```kotlin
-GlobalScope.async {
- workload(n)
-}
-```
-
-Our `workload()` function can be called from a coroutine (or another suspending function), but _cannot_ be called from outside a coroutine. Naturally, `delay()` and `await()` that we used above are themselves declared as `suspend`, and this is why we had to put them inside `runBlocking {}`, `launch {}` or `async {}`.