Skip to content

Commit 1a8de2e

Browse files
committed
Merge remote-tracking branch 'origin/master' into develop
2 parents e9b247e + 45893ce commit 1a8de2e

File tree

16 files changed

+166
-105
lines changed

16 files changed

+166
-105
lines changed

.github/ISSUE_TEMPLATE/guide.md

+20
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
---
2+
name: Issue with the Coroutines guide
3+
about: Problems on https://kotlinlang.org/docs/coroutines-guide.html
4+
title: ''
5+
labels: guide
6+
assignees: ''
7+
8+
---
9+
10+
**Which page?**
11+
12+
Drop a link to a specific page, unless you're reporting something that's missing entirely.
13+
14+
**What can be improved?**
15+
16+
Describe the problematic part. Is it misleading, unclear, or just something that didn’t work for you?
17+
18+
**Is this explained better somewhere else?**
19+
20+
Show us the explanation that made it click for you.

buildSrc/src/main/kotlin/Publishing.kt

+1-1
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,7 @@ fun MavenPom.configureMavenCentralMetadata(project: Project) {
2323

2424
licenses {
2525
license {
26-
name = "The Apache Software License, Version 2.0"
26+
name = "Apache-2.0"
2727
url = "https://www.apache.org/licenses/LICENSE-2.0.txt"
2828
distribution = "repo"
2929
}

docs/topics/cancellation-and-timeouts.md

+17-10
Original file line numberDiff line numberDiff line change
@@ -7,8 +7,8 @@ This section covers coroutine cancellation and timeouts.
77

88
## Cancelling coroutine execution
99

10-
In a long-running application you might need fine-grained control on your background coroutines.
11-
For example, a user might have closed the page that launched a coroutine and now its result
10+
In a long-running application, you might need fine-grained control on your background coroutines.
11+
For example, a user might have closed the page that launched a coroutine, and now its result
1212
is no longer needed and its operation can be cancelled.
1313
The [launch] function returns a [Job] that can be used to cancel the running coroutine:
1414

@@ -142,9 +142,12 @@ which does not rethrow [CancellationException].
142142

143143
## Making computation code cancellable
144144

145-
There are two approaches to making computation code cancellable. The first one is to periodically
146-
invoke a suspending function that checks for cancellation. There is a [yield] function that is a good choice for that purpose.
147-
The other one is to explicitly check the cancellation status. Let us try the latter approach.
145+
There are two approaches to making computation code cancellable.
146+
The first one is periodically invoking a suspending function that checks for cancellation.
147+
There are the [yield] and [ensureActive]
148+
functions, which are great choices for that purpose.
149+
The other one is explicitly checking the cancellation status using [isActive].
150+
Let us try the latter approach.
148151

149152
Replace `while (i < 5)` in the previous example with `while (isActive)` and rerun it.
150153

@@ -158,7 +161,7 @@ fun main() = runBlocking {
158161
var nextPrintTime = startTime
159162
var i = 0
160163
while (isActive) { // cancellable computation loop
161-
// print a message twice a second
164+
// prints a message twice a second
162165
if (System.currentTimeMillis() >= nextPrintTime) {
163166
println("job: I'm sleeping ${i++} ...")
164167
nextPrintTime += 500L
@@ -192,8 +195,10 @@ main: Now I can quit.
192195
## Closing resources with finally
193196

194197
Cancellable suspending functions throw [CancellationException] on cancellation, which can be handled in
195-
the usual way. For example, the `try {...} finally {...}` expression and Kotlin's `use` function execute their
196-
finalization actions normally when a coroutine is cancelled:
198+
the usual way.
199+
For example,
200+
the `try {...} finally {...}` expression and Kotlin's [use](https://kotlinlang.org/api/core/kotlin-stdlib/kotlin.io/use.html)
201+
function execute their finalization actions normally when a coroutine is cancelled:
197202

198203
```kotlin
199204
import kotlinx.coroutines.*
@@ -241,7 +246,7 @@ main: Now I can quit.
241246

242247
Any attempt to use a suspending function in the `finally` block of the previous example causes
243248
[CancellationException], because the coroutine running this code is cancelled. Usually, this is not a
244-
problem, since all well-behaving closing operations (closing a file, cancelling a job, or closing any kind of a
249+
problem, since all well-behaved closing operations (closing a file, cancelling a job, or closing any kind of
245250
communication channel) are usually non-blocking and do not involve any suspending functions. However, in the
246251
rare case when you need to suspend in a cancelled coroutine you can wrap the corresponding code in
247252
`withContext(NonCancellable) {...}` using [withContext] function and [NonCancellable] context as the following example shows:
@@ -327,7 +332,7 @@ Exception in thread "main" kotlinx.coroutines.TimeoutCancellationException: Time
327332

328333
<!--- TEST STARTS_WITH -->
329334

330-
The `TimeoutCancellationException` that is thrown by [withTimeout] is a subclass of [CancellationException].
335+
The [TimeoutCancellationException] that is thrown by [withTimeout] is a subclass of [CancellationException].
331336
We have not seen its stack trace printed on the console before. That is because
332337
inside a cancelled coroutine `CancellationException` is considered to be a normal reason for coroutine completion.
333338
However, in this example we have used `withTimeout` right inside the `main` function.
@@ -489,11 +494,13 @@ This example always prints zero. Resources do not leak.
489494
[Job.join]: https://kotlinlang.org/api/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines/-job/join.html
490495
[CancellationException]: https://kotlinlang.org/api/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines/-cancellation-exception/index.html
491496
[yield]: https://kotlinlang.org/api/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines/yield.html
497+
[ensureActive]: https://kotlinlang.org/api/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines/ensure-active.html
492498
[isActive]: https://kotlinlang.org/api/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines/is-active.html
493499
[CoroutineScope]: https://kotlinlang.org/api/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines/-coroutine-scope/index.html
494500
[withContext]: https://kotlinlang.org/api/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines/with-context.html
495501
[NonCancellable]: https://kotlinlang.org/api/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines/-non-cancellable/index.html
496502
[withTimeout]: https://kotlinlang.org/api/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines/with-timeout.html
503+
[TimeoutCancellationException]: https://kotlinlang.org/api/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines/-timeout-cancellation-exception/index.html
497504
[withTimeoutOrNull]: https://kotlinlang.org/api/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines/with-timeout-or-null.html
498505

499506
<!--- END -->

docs/topics/composing-suspending-functions.md

+7-5
Original file line numberDiff line numberDiff line change
@@ -186,7 +186,9 @@ Note that if we just call [await][Deferred.await] in `println` without first cal
186186
coroutines, this will lead to sequential behavior, since [await][Deferred.await] starts the coroutine
187187
execution and waits for its finish, which is not the intended use-case for laziness.
188188
The use-case for `async(start = CoroutineStart.LAZY)` is a replacement for the
189-
standard `lazy` function in cases when computation of the value involves suspending functions.
189+
standard [lazy](https://kotlinlang.org/api/core/kotlin-stdlib/kotlin/lazy.html) function in cases
190+
when computation of the value involves suspending functions.
191+
190192

191193
## Async-style functions
192194

@@ -291,10 +293,10 @@ concurrency, as shown in the section below.
291293

292294
## Structured concurrency with async
293295

294-
Let us take the [Concurrent using async](#concurrent-using-async) example and extract a function that
295-
concurrently performs `doSomethingUsefulOne` and `doSomethingUsefulTwo` and returns the sum of their results.
296-
Because the [async] coroutine builder is defined as an extension on [CoroutineScope], we need to have it in the
297-
scope and that is what the [coroutineScope][_coroutineScope] function provides:
296+
Let's refactor the [Concurrent using async](#concurrent-using-async) example into a function that runs
297+
`doSomethingUsefulOne` and `doSomethingUsefulTwo` concurrently and returns their combined results.
298+
Since [async] is a [CoroutineScope] extension,
299+
we'll use the [coroutineScope][_coroutineScope] function to provide the necessary scope:
298300

299301
```kotlin
300302
suspend fun concurrentSum(): Int = coroutineScope {

docs/topics/coroutine-context-and-dispatchers.md

+41-27
Original file line numberDiff line numberDiff line change
@@ -246,9 +246,15 @@ fun main() {
246246
>
247247
{style="note"}
248248

249-
It demonstrates several new techniques. One is using [runBlocking] with an explicitly specified context, and
250-
the other one is using the [withContext] function to change the context of a coroutine while still staying in the
251-
same coroutine, as you can see in the output below:
249+
The example above demonstrates new techniques in coroutine usage.
250+
251+
The first technique shows how to use [runBlocking] with a specified context.
252+
The second technique involves calling [withContext],
253+
which may suspend the current coroutine and switch to a new context—provided the new context differs from the existing one.
254+
Specifically, if you specify a different [CoroutineDispatcher], extra dispatches are required:
255+
the block is scheduled on the new dispatcher, and once it finishes, execution returns to the original dispatcher.
256+
257+
As a result, the output of the above code is:
252258

253259
```text
254260
[Ctx1 @coroutine#1] Started in ctx1
@@ -258,8 +264,8 @@ same coroutine, as you can see in the output below:
258264

259265
<!--- TEST -->
260266

261-
Note that this example also uses the `use` function from the Kotlin standard library to release threads
262-
created with [newSingleThreadContext] when they are no longer needed.
267+
The example above uses the `use` function from the Kotlin standard library
268+
to properly release thread resources created by [newSingleThreadContext] when they're no longer needed.
263269

264270
## Job in the context
265271

@@ -281,7 +287,7 @@ fun main() = runBlocking<Unit> {
281287
>
282288
{style="note"}
283289

284-
In the [debug mode](#debugging-coroutines-and-threads), it outputs something like this:
290+
In [debug mode](#debugging-coroutines-and-threads), it outputs something like this:
285291

286292
```
287293
My job is "coroutine#1":BlockingCoroutine{Active}@6d311334
@@ -300,12 +306,12 @@ the [Job] of the new coroutine becomes
300306
a _child_ of the parent coroutine's job. When the parent coroutine is cancelled, all its children
301307
are recursively cancelled, too.
302308

303-
However, this parent-child relation can be explicitly overriden in one of two ways:
309+
However, this parent-child relation can be explicitly overridden in one of two ways:
304310

305311
1. When a different scope is explicitly specified when launching a coroutine (for example, `GlobalScope.launch`),
306-
then it does not inherit a `Job` from the parent scope.
307-
2. When a different `Job` object is passed as the context for the new coroutine (as shown in the example below),
308-
then it overrides the `Job` of the parent scope.
312+
it does not inherit a `Job` from the parent scope.
313+
2. When a different `Job` object is passed as the context for the new coroutine (as shown in the example below),
314+
it overrides the `Job` of the parent scope.
309315

310316
In both cases, the launched coroutine is not tied to the scope it was launched from and operates independently.
311317

@@ -356,7 +362,8 @@ job1: I am not affected by cancellation of the request
356362

357363
## Parental responsibilities
358364

359-
A parent coroutine always waits for completion of all its children. A parent does not have to explicitly track
365+
A parent coroutine always waits for the completion of all its children.
366+
A parent does not have to explicitly track
360367
all the children it launches, and it does not have to use [Job.join] to wait for them at the end:
361368

362369
```kotlin
@@ -480,11 +487,15 @@ I'm working in thread DefaultDispatcher-worker-1 @test#2
480487

481488
## Coroutine scope
482489

483-
Let us put our knowledge about contexts, children and jobs together. Assume that our application has
484-
an object with a lifecycle, but that object is not a coroutine. For example, we are writing an Android application
485-
and launch various coroutines in the context of an Android activity to perform asynchronous operations to fetch
486-
and update data, do animations, etc. All of these coroutines must be cancelled when the activity is destroyed
487-
to avoid memory leaks. We, of course, can manipulate contexts and jobs manually to tie the lifecycles of the activity
490+
Let us put our knowledge about contexts, children, and jobs together.
491+
Assume that our application has an object with a lifecycle, but that object is not a coroutine.
492+
For example,
493+
we are writing an Android application,
494+
and launching various coroutines in the context of an Android activity
495+
to perform asynchronous operations to fetch and update data,
496+
do animations, etc. These coroutines must be cancelled when the activity is destroyed
497+
to avoid memory leaks.
498+
We, of course, can manipulate contexts and jobs manually to tie the lifecycles of the activity
488499
and its coroutines, but `kotlinx.coroutines` provides an abstraction encapsulating that: [CoroutineScope].
489500
You should be already familiar with the coroutine scope as all coroutine builders are declared as extensions on it.
490501

@@ -521,8 +532,9 @@ For the demo, we launch ten coroutines that delay for a different time:
521532
```
522533

523534
In our main function we create the activity, call our test `doSomething` function, and destroy the activity after 500ms.
524-
This cancels all the coroutines that were launched from `doSomething`. We can see that because after the destruction
525-
of the activity no more messages are printed, even if we wait a little longer.
535+
This cancels all the coroutines that were launched from `doSomething`.
536+
We can see that because after the destruction
537+
of the activity, no more messages are printed, even if we wait a little longer.
526538

527539
<!--- CLEAR -->
528540

@@ -577,16 +589,16 @@ Destroying activity!
577589
<!--- TEST -->
578590

579591
As you can see, only the first two coroutines print a message and the others are cancelled
580-
by a single invocation of `job.cancel()` in `Activity.destroy()`.
592+
by a single invocation of [`mainScope.cancel()`][CoroutineScope.cancel] in `Activity.destroy()`.
581593

582-
> Note, that Android has first-party support for coroutine scope in all entities with the lifecycle.
594+
> Note that Android has first-party support for coroutine scope in all entities with the lifecycle.
583595
> See [the corresponding documentation](https://developer.android.com/topic/libraries/architecture/coroutines#lifecyclescope).
584596
>
585597
{style="note"}
586598

587599
### Thread-local data
588600

589-
Sometimes it is convenient to have an ability to pass some thread-local data to or between coroutines.
601+
Sometimes it is convenient to be able to pass some thread-local data to or between coroutines.
590602
However, since they are not bound to any particular thread, this will likely lead to boilerplate if done manually.
591603

592604
For [`ThreadLocal`](https://docs.oracle.com/javase/8/docs/api/java/lang/ThreadLocal.html),
@@ -620,8 +632,8 @@ fun main() = runBlocking<Unit> {
620632
>
621633
{style="note"}
622634

623-
In this example we launch a new coroutine in a background thread pool using [Dispatchers.Default], so
624-
it works on a different thread from the thread pool, but it still has the value of the thread local variable
635+
In this example, we launch a new coroutine in a background thread pool using [Dispatchers.Default], so
636+
it works on different threads from the thread pool, but it still has the value of the thread local variable
625637
that we specified using `threadLocal.asContextElement(value = "launch")`,
626638
no matter which thread the coroutine is executed on.
627639
Thus, the output (with [debug](#debugging-coroutines-and-threads)) is:
@@ -636,7 +648,7 @@ Post-main, current thread: Thread[main @coroutine#1,5,main], thread local value:
636648
<!--- TEST FLEXIBLE_THREAD -->
637649

638650
It's easy to forget to set the corresponding context element. The thread-local variable accessed from the coroutine may
639-
then have an unexpected value, if the thread running the coroutine is different.
651+
then have an unexpected value if the thread running the coroutine is different.
640652
To avoid such situations, it is recommended to use the [ensurePresent] method
641653
and fail-fast on improper usages.
642654

@@ -646,11 +658,12 @@ It has one key limitation, though: when a thread-local is mutated, a new value i
646658
Use [withContext] to update the value of the thread-local in a coroutine, see [asContextElement] for more details.
647659

648660
Alternatively, a value can be stored in a mutable box like `class Counter(var i: Int)`, which is, in turn,
649-
stored in a thread-local variable. However, in this case you are fully responsible to synchronize
661+
stored in a thread-local variable.
662+
However, in this case, you are fully responsible to synchronize
650663
potentially concurrent modifications to the variable in this mutable box.
651664

652-
For advanced usage, for example for integration with logging MDC, transactional contexts or any other libraries
653-
which internally use thread-locals for passing data, see the documentation of the [ThreadContextElement] interface
665+
For advanced usage, for example, for integration with logging MDC, transactional contexts or any other libraries
666+
that internally use thread-locals for passing data, see the documentation of the [ThreadContextElement] interface
654667
that should be implemented.
655668

656669
<!--- MODULE kotlinx-coroutines-core -->
@@ -676,6 +689,7 @@ that should be implemented.
676689
[CoroutineScope()]: https://kotlinlang.org/api/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines/-coroutine-scope.html
677690
[MainScope()]: https://kotlinlang.org/api/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines/-main-scope.html
678691
[Dispatchers.Main]: https://kotlinlang.org/api/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines/-dispatchers/-main.html
692+
[CoroutineScope.cancel]: https://kotlinlang.org/api/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines/cancel.html
679693
[asContextElement]: https://kotlinlang.org/api/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines/as-context-element.html
680694
[ensurePresent]: https://kotlinlang.org/api/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines/ensure-present.html
681695
[ThreadContextElement]: https://kotlinlang.org/api/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines/-thread-context-element/index.html

docs/topics/coroutines-basics.md

+2-2
Original file line numberDiff line numberDiff line change
@@ -212,8 +212,8 @@ Done
212212
## An explicit job
213213

214214
A [launch] coroutine builder returns a [Job] object that is a handle to the launched coroutine and can be
215-
used to explicitly wait for its completion. For example, you can wait for completion of the child coroutine
216-
and then print "Done" string:
215+
used to wait for its completion explicitly.
216+
For example, you can wait for the completion of the child coroutine and then print the "Done" string:
217217

218218
```kotlin
219219
import kotlinx.coroutines.*

docs/topics/debug-coroutines-with-idea.md

+2-2
Original file line numberDiff line numberDiff line change
@@ -108,12 +108,12 @@ Using IntelliJ IDEA debugger, you can dig deeper into each coroutine to debug yo
108108

109109
If you use `suspend` functions, in the debugger, you might see the "was optimized out" text next to a variable's name:
110110
111-
![Variable "a" was optimized out](variable-optimised-out.png)
111+
![Variable "a" was optimized out](variable-optimised-out.png){width=480}
112112
113113
This text means that the variable's lifetime was decreased, and the variable doesn't exist anymore.
114114
It is difficult to debug code with optimized variables because you don't see their values.
115115
You can disable this behavior with the `-Xdebug` compiler option.
116116

117117
> __Never use this flag in production__: `-Xdebug` can [cause memory leaks](https://youtrack.jetbrains.com/issue/KT-48678/Coroutine-debugger-disable-was-optimised-out-compiler-feature#focus=Comments-27-6015585.0-0).
118118
>
119-
{style="warning"}
119+
{style="warning"}

0 commit comments

Comments
 (0)