From e75eb26cd1e7edbd1fe6c2fc19fdf6b82c9bc629 Mon Sep 17 00:00:00 2001 From: Adam Howard Date: Tue, 2 Jun 2020 11:17:46 +0100 Subject: [PATCH 1/3] regular doc rewording 'get full code here' -> 'get the full code here' --- docs/basics.md | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/docs/basics.md b/docs/basics.md index c5e931c58a..ff6f6a5870 100644 --- a/docs/basics.md +++ b/docs/basics.md @@ -41,7 +41,7 @@ fun main() { -> You can get full code [here](../kotlinx-coroutines-core/jvm/test/guide/example-basic-01.kt). +> You can get the full code [here](../kotlinx-coroutines-core/jvm/test/guide/example-basic-01.kt). You will see the following result: @@ -95,7 +95,7 @@ fun main() { -> You can get full code [here](../kotlinx-coroutines-core/jvm/test/guide/example-basic-02.kt). +> You can get the full code [here](../kotlinx-coroutines-core/jvm/test/guide/example-basic-02.kt). @@ -379,7 +379,7 @@ fun main() = runBlocking { -> You can get full code [here](../kotlinx-coroutines-core/jvm/test/guide/example-basic-09.kt). +> You can get the full code [here](../kotlinx-coroutines-core/jvm/test/guide/example-basic-09.kt). You can run and see that it prints three lines and terminates: From 015809a774ce76db1f097b8e640297d27a9af193 Mon Sep 17 00:00:00 2001 From: Adam Howard Date: Tue, 2 Jun 2020 11:21:34 +0100 Subject: [PATCH 2/3] improve grammar in docs/basics --- docs/basics.md | 43 ++++++++++++++++++++++--------------------- 1 file changed, 22 insertions(+), 21 deletions(-) diff --git a/docs/basics.md b/docs/basics.md index ff6f6a5870..60ce14f66e 100644 --- a/docs/basics.md +++ b/docs/basics.md @@ -57,24 +57,24 @@ They are launched with [launch] _coroutine builder_ in a context of some [Corout Here we are launching a new coroutine in the [GlobalScope], meaning that the lifetime of the new coroutine is limited only by the lifetime of the whole application. -You can achieve the same result replacing -`GlobalScope.launch { ... }` with `thread { ... }` and `delay(...)` with `Thread.sleep(...)`. +You can achieve the same result by replacing +`GlobalScope.launch { ... }` with `thread { ... }`, and `delay(...)` with `Thread.sleep(...)`. Try it (don't forget to import `kotlin.concurrent.thread`). -If you start by replacing `GlobalScope.launch` by `thread`, the compiler produces the following error: +If you start by replacing `GlobalScope.launch` with `thread`, the compiler produces the following error: ``` Error: Kotlin: Suspend functions are only allowed to be called from a coroutine or another suspend function ``` -That is because [delay] is a special _suspending function_ that does not block a thread, but _suspends_ -coroutine and it can be only used from a coroutine. +That is because [delay] is a special _suspending function_ that does not block a thread, but _suspends_ the +coroutine, and it can be only used from a coroutine. ### Bridging blocking and non-blocking worlds The first example mixes _non-blocking_ `delay(...)` and _blocking_ `Thread.sleep(...)` in the same code. It is easy to lose track of which one is blocking and which one is not. -Let's be explicit about blocking using [runBlocking] coroutine builder: +Let's be explicit about blocking using the [runBlocking] coroutine builder:
@@ -195,7 +195,7 @@ the background job in any way. Much better. There is still something to be desired for practical usage of coroutines. When we use `GlobalScope.launch`, we create a top-level coroutine. Even though it is light-weight, it still consumes some memory resources while it runs. If we forget to keep a reference to the newly launched -coroutine it still runs. What if the code in the coroutine hangs (for example, we erroneously +coroutine, it still runs. What if the code in the coroutine hangs (for example, we erroneously delay for too long), what if we launched too many coroutines and ran out of memory? Having to manually keep references to all the launched coroutines and [join][Job.join] them is error-prone. @@ -203,7 +203,7 @@ There is a better solution. We can use structured concurrency in our code. Instead of launching coroutines in the [GlobalScope], just like we usually do with threads (threads are always global), we can launch coroutines in the specific scope of the operation we are performing. -In our example, we have `main` function that is turned into a coroutine using [runBlocking] coroutine builder. +In our example, we have a `main` function that is turned into a coroutine using a [runBlocking] coroutine builder. Every coroutine builder, including `runBlocking`, adds an instance of [CoroutineScope] to the scope of its code block. We can launch coroutines in this scope without having to `join` them explicitly, because an outer coroutine (`runBlocking` in our example) does not complete until all the coroutines launched @@ -233,12 +233,12 @@ World! --> ### Scope builder -In addition to the coroutine scope provided by different builders, it is possible to declare your own scope using -[coroutineScope] builder. It creates a coroutine scope and does not complete until all launched children -complete. -[runBlocking] and [coroutineScope] may look similar because they both wait for its body and all its children to complete. -The main difference between these two is that the [runBlocking] method _blocks_ the current thread for waiting, +In addition to the coroutine scope provided by different builders, it is possible to declare your own scope using the +[coroutineScope] builder. It creates a coroutine scope and does not complete until all launched children complete. + +[runBlocking] and [coroutineScope] may look similar because they both wait for their body and all its children to complete. +The main difference is that the [runBlocking] method _blocks_ the current thread for waiting, while [coroutineScope] just suspends, releasing the underlying thread for other usages. Because of that difference, [runBlocking] is a regular function and [coroutineScope] is a suspending function. @@ -280,16 +280,16 @@ Task from nested launch Coroutine scope is over --> -Note that right after "Task from coroutine scope" message, while waiting for nested launch, - "Task from runBlocking" is executed and printed, though coroutineScope is not completed yet. +Note that right after the "Task from coroutine scope" message (while waiting for nested launch) + "Task from runBlocking" is executed and printed — even though the coroutineScope is not completed yet. ### Extract function refactoring Let's extract the block of code inside `launch { ... }` into a separate function. When you -perform "Extract function" refactoring on this code you get a new function with `suspend` modifier. -That is your first _suspending function_. Suspending functions can be used inside coroutines +perform "Extract function" refactoring on this code, you get a new function with the `suspend` modifier. +This is your first _suspending function_. Suspending functions can be used inside coroutines just like regular functions, but their additional feature is that they can, in turn, -use other suspending functions, like `delay` in this example, to _suspend_ execution of a coroutine. +use other suspending functions (like `delay` in this example) to _suspend_ execution of a coroutine.
@@ -319,11 +319,11 @@ World! But what if the extracted function contains a coroutine builder which is invoked on the current scope? -In this case `suspend` modifier on the extracted function is not enough. Making `doWorld` an extension -method on `CoroutineScope` is one of the solutions, but it may not always be applicable as it does not make API clearer. +In this case, the `suspend` modifier on the extracted function is not enough. Making `doWorld` an extension +method on `CoroutineScope` is one of the solutions, but it may not always be applicable as it does not make the API clearer. The idiomatic solution is to have either an explicit `CoroutineScope` as a field in a class containing the target function or an implicit one when the outer class implements `CoroutineScope`. -As a last resort, [CoroutineScope(coroutineContext)][CoroutineScope()] can be used, but such approach is structurally unsafe +As a last resort, [CoroutineScope(coroutineContext)][CoroutineScope()] can be used, but such an approach is structurally unsafe because you no longer have control on the scope of execution of this method. Only private APIs can use this builder. ### Coroutines ARE light-weight @@ -352,6 +352,7 @@ fun main() = runBlocking { It launches 100K coroutines and, after a second, each coroutine prints a dot. + Now, try that with threads. What would happen? (Most likely your code will produce some sort of out-of-memory error) ### Global coroutines are like daemon threads From 52e8af4a2f504c8b19eba3f207d34dce1d5f203e Mon Sep 17 00:00:00 2001 From: Adam Howard Date: Tue, 2 Jun 2020 11:53:55 +0100 Subject: [PATCH 3/3] in all documentation, 'get full code here' -> 'get the full code here' --- docs/cancellation-and-timeouts.md | 14 ++++++------- docs/channels.md | 20 +++++++++--------- docs/composing-suspending-functions.md | 12 +++++------ docs/coroutine-context-and-dispatchers.md | 22 ++++++++++---------- docs/exception-handling.md | 18 ++++++++-------- docs/select-expression.md | 10 ++++----- docs/shared-mutable-state-and-concurrency.md | 14 ++++++------- ui/coroutines-guide-ui.md | 14 ++++++------- 8 files changed, 62 insertions(+), 62 deletions(-) diff --git a/docs/cancellation-and-timeouts.md b/docs/cancellation-and-timeouts.md index b51c45c941..d8d5b7bad4 100644 --- a/docs/cancellation-and-timeouts.md +++ b/docs/cancellation-and-timeouts.md @@ -49,7 +49,7 @@ fun main() = runBlocking {
-> You can get full code [here](../kotlinx-coroutines-core/jvm/test/guide/example-cancel-01.kt). +> You can get the full code [here](../kotlinx-coroutines-core/jvm/test/guide/example-cancel-01.kt). It produces the following output: @@ -104,7 +104,7 @@ fun main() = runBlocking {
-> You can get full code [here](../kotlinx-coroutines-core/jvm/test/guide/example-cancel-02.kt). +> You can get the full code [here](../kotlinx-coroutines-core/jvm/test/guide/example-cancel-02.kt). Run it to see that it continues to print "I'm sleeping" even after cancellation until the job completes by itself after five iterations. @@ -156,7 +156,7 @@ fun main() = runBlocking { -> You can get full code [here](../kotlinx-coroutines-core/jvm/test/guide/example-cancel-03.kt). +> You can get the full code [here](../kotlinx-coroutines-core/jvm/test/guide/example-cancel-03.kt). As you can see, now this loop is cancelled. [isActive] is an extension property available inside the coroutine via the [CoroutineScope] object. @@ -203,7 +203,7 @@ fun main() = runBlocking { -> You can get full code [here](../kotlinx-coroutines-core/jvm/test/guide/example-cancel-04.kt). +> You can get the full code [here](../kotlinx-coroutines-core/jvm/test/guide/example-cancel-04.kt). Both [join][Job.join] and [cancelAndJoin] wait for all finalization actions to complete, so the example above produces the following output: @@ -259,7 +259,7 @@ fun main() = runBlocking { -> You can get full code [here](../kotlinx-coroutines-core/jvm/test/guide/example-cancel-05.kt). +> You can get the full code [here](../kotlinx-coroutines-core/jvm/test/guide/example-cancel-05.kt).