Skip to content

Commit 117dcb8

Browse files
committed
Merge branch 'develop' into new-channels-select
2 parents 70c4f92 + 5e5dcd7 commit 117dcb8

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

42 files changed

+397
-169
lines changed

CHANGES.md

+68-1
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,72 @@
11
# Change log for kotlinx.coroutines
22

3+
## Version 1.6.0
4+
5+
Note that this is a full changelog relative to 1.5.2 version. Changelog relative to 1.6.0-RC3 can be found in the end.
6+
7+
### kotlinx-coroutines-test rework
8+
9+
* `kotlinx-coroutines-test` became a multiplatform library usable from K/JVM, K/JS, and K/N.
10+
* Its API was completely reworked to address long-standing issues with consistency, structured concurrency and correctness (#1203, #1609, #2379, #1749, #1204, #1390, #1222, #1395, #1881, #1910, #1772, #1626, #1742, #2082, #2102, #2405, #2462
11+
).
12+
* The old API is deprecated for removal, but the new API is based on the similar concepts ([README](kotlinx-coroutines-test/README.md)), and the migration path is designed to be graceful: [migration guide](kotlinx-coroutines-test/MIGRATION.md).
13+
14+
### Dispatchers
15+
16+
* Introduced `CoroutineDispatcher.limitedParallelism` that allows obtaining a view of the original dispatcher with limited parallelism (#2919).
17+
* `Dispatchers.IO.limitedParallelism` usages ignore the bound on the parallelism level of `Dispatchers.IO` itself to avoid starvation (#2943).
18+
* Introduced new `Dispatchers.shutdown` method for containerized environments (#2558).
19+
* `newSingleThreadContext` and `newFixedThreadPoolContext` are promoted to delicate API (#2919).
20+
21+
### Breaking changes
22+
23+
* When racing with cancellation, the `future` builder no longer reports unhandled exceptions into the global `CoroutineExceptionHandler`. Thanks @vadimsemenov! (#2774, #2791).
24+
* `Mutex.onLock` is deprecated for removal (#2794).
25+
* `Dispatchers.Main` is now used as the default source of time for `delay` and `withTimeout` when present(#2972).
26+
* To opt-out from this behaviour, `kotlinx.coroutines.main.delay` system property can be set to `false`.
27+
* Java target of coroutines build is now 8 instead of 6 (#1589).
28+
29+
### Bug fixes and improvements
30+
31+
* Kotlin is updated to 1.6.0.
32+
* Kotlin/Native [new memory model](https://blog.jetbrains.com/kotlin/2021/08/try-the-new-kotlin-native-memory-manager-development-preview/) is now supported in regular builds of coroutines conditionally depending on whether `kotlin.native.binary.memoryModel` is enabled (#2914).
33+
* Introduced `CopyableThreadContextElement` for mutable context elements shared among multiple coroutines. Thanks @yorickhenning! (#2893).
34+
* `transformWhile`, `awaitClose`, `ProducerScope`, `merge`, `runningFold`, `runingReduce`, and `scan` are promoted to stable API (#2971).
35+
* `SharedFlow.subscriptionCount` no longer conflates incoming updates and gives all subscribers a chance to observe a short-lived subscription (#2488, #2863, #2871).
36+
* `Flow` exception transparency mechanism is improved to be more exception-friendly (#3017, #2860).
37+
* Cancellation from `flat*` operators that leverage multiple coroutines is no longer propagated upstream (#2964).
38+
* `SharedFlow.collect` now returns `Nothing` (#2789, #2502).
39+
* `DisposableHandle` is now `fun interface`, and corresponding inline extension is removed (#2790).
40+
* `FlowCollector` is now `fun interface`, and corresponding inline extension is removed (#3047).
41+
* Deprecation level of all previously deprecated signatures is raised (#3024).
42+
* The version file is shipped with each JAR as a resource (#2941).
43+
* Unhandled exceptions on K/N are passed to the standard library function `processUnhandledException` (#2981).
44+
* A direct executor is used for `Task` callbacks in `kotlinx-coroutines-play-services` (#2990).
45+
* Metadata of coroutines artifacts leverages Gradle platform to have all versions of dependencies aligned (#2865).
46+
* Default `CoroutineExceptionHandler` is loaded eagerly and does not invoke `ServiceLoader` on its exception-handling path (#2552).
47+
* Fixed the R8 rules for `ServiceLoader` optimization (#2880).
48+
* Fixed BlockHound integration false-positives (#2894, #2866, #2937).
49+
* Fixed the exception handler being invoked several times on Android, thanks to @1zaman (#3056).
50+
* `SendChannel.trySendBlocking` is now available on Kotlin/Native (#3064).
51+
* The exception recovery mechanism now uses `ClassValue` when available (#2997).
52+
* JNA is updated to 5.9.0 to support Apple M1 (#3001).
53+
* Obsolete method on internal `Delay` interface is deprecated (#2979).
54+
* Support of deprecated `CommonPool` is removed.
55+
* `@ExperimentalTime` is no longer needed for methods that use `Duration` (#3041).
56+
* JDK 1.6 is no longer required for building the project (#3043).
57+
* New version of Dokka is used, fixing the memory leak when building the coroutines and providing brand new reference visuals (https://kotlin.github.io/kotlinx.coroutines/) (#3051, #3054).
58+
59+
### Changelog relative to version 1.6.0-RC3
60+
61+
* Restored MPP binary compatibility on K/JS and K/N (#3104).
62+
* Fixed Dispatchers.Main not being fully initialized on Android and Swing (#3101).
63+
64+
## Version 1.6.0-RC3
65+
66+
* Fixed the error in 1.6.0-RC2 because of which `Flow.collect` couldn't be called due to the `@InternalCoroutinesApi` annotation (#3082)
67+
* Fixed some R8 warnings introduced in 1.6.0-RC (#3090)
68+
* `TestCoroutineScheduler` now provides a `TimeSource` with its virtual time via the `timeSource` property. Thanks @hfhbd! (#3087)
69+
370
## Version 1.6.0-RC2
471

572
* `@ExperimentalTime` is no longer needed for methods that use `Duration` (#3041).
@@ -23,7 +90,7 @@
2390

2491
### Dispatchers
2592

26-
* * Introduced `CoroutineDispatcher.limitedParallelism` that allows obtaining a view of the original dispatcher with limited parallelism (#2919).
93+
* Introduced `CoroutineDispatcher.limitedParallelism` that allows obtaining a view of the original dispatcher with limited parallelism (#2919).
2794
* `Dispatchers.IO.limitedParallelism` usages ignore the bound on the parallelism level of `Dispatchers.IO` itself to avoid starvation (#2943).
2895
* Introduced new `Dispatchers.shutdown` method for containerized environments (#2558).
2996
* `newSingleThreadContext` and `newFixedThreadPoolContext` are promoted to delicate API (#2919).

README.md

+7-7
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22

33
[![official JetBrains project](https://jb.gg/badges/official.svg)](https://confluence.jetbrains.com/display/ALL/JetBrains+on+GitHub)
44
[![GitHub license](https://img.shields.io/badge/license-Apache%20License%202.0-blue.svg?style=flat)](https://www.apache.org/licenses/LICENSE-2.0)
5-
[![Download](https://img.shields.io/maven-central/v/org.jetbrains.kotlinx/kotlinx-coroutines-core/1.6.0-RC2)](https://search.maven.org/artifact/org.jetbrains.kotlinx/kotlinx-coroutines-core/1.6.0-RC2/pom)
5+
[![Download](https://img.shields.io/maven-central/v/org.jetbrains.kotlinx/kotlinx-coroutines-core/1.6.0)](https://search.maven.org/artifact/org.jetbrains.kotlinx/kotlinx-coroutines-core/1.6.0/pom)
66
[![Kotlin](https://img.shields.io/badge/kotlin-1.6.0-blue.svg?logo=kotlin)](http://kotlinlang.org)
77
[![Slack channel](https://img.shields.io/badge/chat-slack-green.svg?logo=slack)](https://kotlinlang.slack.com/messages/coroutines/)
88

@@ -83,7 +83,7 @@ Add dependencies (you can also add other modules that you need):
8383
<dependency>
8484
<groupId>org.jetbrains.kotlinx</groupId>
8585
<artifactId>kotlinx-coroutines-core</artifactId>
86-
<version>1.6.0-RC2</version>
86+
<version>1.6.0</version>
8787
</dependency>
8888
```
8989

@@ -101,7 +101,7 @@ Add dependencies (you can also add other modules that you need):
101101

102102
```groovy
103103
dependencies {
104-
implementation 'org.jetbrains.kotlinx:kotlinx-coroutines-core:1.6.0-RC2'
104+
implementation 'org.jetbrains.kotlinx:kotlinx-coroutines-core:1.6.0'
105105
}
106106
```
107107

@@ -127,7 +127,7 @@ Add dependencies (you can also add other modules that you need):
127127

128128
```groovy
129129
dependencies {
130-
implementation("org.jetbrains.kotlinx:kotlinx-coroutines-core:1.6.0-RC2")
130+
implementation("org.jetbrains.kotlinx:kotlinx-coroutines-core:1.6.0")
131131
}
132132
```
133133

@@ -147,7 +147,7 @@ Add [`kotlinx-coroutines-android`](ui/kotlinx-coroutines-android)
147147
module as a dependency when using `kotlinx.coroutines` on Android:
148148

149149
```groovy
150-
implementation 'org.jetbrains.kotlinx:kotlinx-coroutines-android:1.6.0-RC2'
150+
implementation 'org.jetbrains.kotlinx:kotlinx-coroutines-android:1.6.0'
151151
```
152152

153153
This gives you access to the Android [Dispatchers.Main]
@@ -180,7 +180,7 @@ In common code that should get compiled for different platforms, you can add a d
180180
```groovy
181181
commonMain {
182182
dependencies {
183-
implementation("org.jetbrains.kotlinx:kotlinx-coroutines-core:1.6.0-RC2")
183+
implementation("org.jetbrains.kotlinx:kotlinx-coroutines-core:1.6.0")
184184
}
185185
}
186186
```
@@ -192,7 +192,7 @@ Platform-specific dependencies are recommended to be used only for non-multiplat
192192
#### JS
193193

194194
Kotlin/JS version of `kotlinx.coroutines` is published as
195-
[`kotlinx-coroutines-core-js`](https://search.maven.org/artifact/org.jetbrains.kotlinx/kotlinx-coroutines-core-js/1.6.0-RC2/jar)
195+
[`kotlinx-coroutines-core-js`](https://search.maven.org/artifact/org.jetbrains.kotlinx/kotlinx-coroutines-core-js/1.6.0/jar)
196196
(follow the link to get the dependency declaration snippet) and as [`kotlinx-coroutines-core`](https://www.npmjs.com/package/kotlinx-coroutines-core) NPM package.
197197

198198
#### Native

build.gradle

+4-2
Original file line numberDiff line numberDiff line change
@@ -58,6 +58,7 @@ buildscript {
5858
classpath "com.moowork.gradle:gradle-node-plugin:$gradle_node_version"
5959
classpath "org.jetbrains.kotlinx:binary-compatibility-validator:$binary_compatibility_validator_version"
6060
classpath "ru.vyarus:gradle-animalsniffer-plugin:1.5.3" // Android API check
61+
classpath "org.jetbrains.kotlinx:kover:$kover_version"
6162

6263
// JMH plugins
6364
classpath "com.github.jengelman.gradle.plugins:shadow:5.1.0"
@@ -105,7 +106,8 @@ allprojects {
105106
}
106107

107108
apply plugin: "binary-compatibility-validator"
108-
apply plugin: 'base'
109+
apply plugin: "base"
110+
apply plugin: "kover-conventions"
109111

110112
apiValidation {
111113
ignoredProjects += unpublished + ["kotlinx-coroutines-bom"]
@@ -303,7 +305,7 @@ def publishTasks = getTasksByName("publish", true) + getTasksByName("publishNpm"
303305

304306
task deploy(dependsOn: publishTasks)
305307

306-
apply plugin: 'animalsniffer-convention'
308+
apply plugin: "animalsniffer-conventions"
307309

308310
clean.dependsOn gradle.includedBuilds.collect { it.task(':clean') }
309311

buildSrc/build.gradle.kts

+1
Original file line numberDiff line numberDiff line change
@@ -60,4 +60,5 @@ dependencies {
6060
exclude(group = "org.jetbrains.kotlin", module = "kotlin-stdlib")
6161
}
6262
implementation("ru.vyarus:gradle-animalsniffer-plugin:1.5.3") // Android API check
63+
implementation("org.jetbrains.kotlinx:kover:${version("kover")}")
6364
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,54 @@
1+
import kotlinx.kover.api.*
2+
import kotlinx.kover.tasks.*
3+
4+
/*
5+
* Copyright 2016-2021 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
6+
*/
7+
apply(plugin = "kover")
8+
9+
val notCovered = sourceless + internal + unpublished
10+
11+
val expectedCoverage = mutableMapOf(
12+
// These have lower coverage in general, it can be eventually fixed
13+
"kotlinx-coroutines-swing" to 70,
14+
"kotlinx-coroutines-android" to 50,
15+
"kotlinx-coroutines-javafx" to 39, // JavaFx is not tested on TC because its graphic subsystem cannot be initialized in headless mode
16+
17+
// TODO figure it out, these probably should be fixed
18+
"kotlinx-coroutines-debug" to 84,
19+
"kotlinx-coroutines-reactive" to 65,
20+
"kotlinx-coroutines-reactor" to 65,
21+
"kotlinx-coroutines-rx2" to 78,
22+
"kotlinx-coroutines-slf4j" to 81
23+
)
24+
25+
extensions.configure<KoverExtension> {
26+
disabledProjects = notCovered
27+
/*
28+
* Is explicitly enabled on TC in a separate build step.
29+
* Examples:
30+
* ./gradlew :p:check -- doesn't verify coverage
31+
* ./gradlew :p:check -Pkover.enabled=true -- verifies coverage
32+
* ./gradlew :p:koverReport -Pkover.enabled=true -- generates report
33+
*/
34+
isDisabled = !(properties["kover.enabled"]?.toString()?.toBoolean() ?: false)
35+
}
36+
37+
subprojects {
38+
val projectName = name
39+
if (projectName in notCovered) return@subprojects
40+
tasks.withType<KoverVerificationTask> {
41+
rule {
42+
bound {
43+
/*
44+
* 85 is our baseline that we aim to raise to 90+.
45+
* Missing coverage is typically due to bugs in the agent
46+
* (e.g. signatures deprecated with an error are counted),
47+
* sometimes it's various diagnostic `toString` or `catch` for OOMs/VerificationErrors,
48+
* but some places are definitely worth visiting.
49+
*/
50+
minValue = expectedCoverage[projectName] ?: 85 // COVERED_LINES_PERCENTAGE
51+
}
52+
}
53+
}
54+
}

gradle.properties

+3-2
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
#
44

55
# Kotlin
6-
version=1.6.0-RC2-SNAPSHOT
6+
version=1.6.0-SNAPSHOT
77
group=org.jetbrains.kotlinx
88
kotlin_version=1.6.0
99

@@ -22,7 +22,8 @@ rxjava2_version=2.2.8
2222
rxjava3_version=3.0.2
2323
javafx_version=11.0.2
2424
javafx_plugin_version=0.0.8
25-
binary_compatibility_validator_version=0.8.0-RC
25+
binary_compatibility_validator_version=0.8.0
26+
kover_version=0.5.0-RC2
2627
blockhound_version=1.0.2.RELEASE
2728
jna_version=5.9.0
2829

integration/kotlinx-coroutines-guava/README.md

+1-1
Original file line numberDiff line numberDiff line change
@@ -62,6 +62,6 @@ Integration with Guava [ListenableFuture](https://github.com/google/guava/wiki/L
6262

6363
<!--- INDEX com.google.common.util.concurrent -->
6464

65-
[com.google.common.util.concurrent.ListenableFuture]: https://kotlin.github.io/kotlinx.coroutines/https://google.github.io/guava/releases/28.0-jre/api/docs/com/google/common/util/concurrent/ListenableFuture.html
65+
[com.google.common.util.concurrent.ListenableFuture]: https://kotlin.github.io/kotlinx.coroutines/https://google.github.io/guava/releases/31.0.1-jre/api/docs/com/google/common/util/concurrent/ListenableFuture.html
6666

6767
<!--- END -->

integration/kotlinx-coroutines-guava/build.gradle.kts

+6-1
Original file line numberDiff line numberDiff line change
@@ -2,12 +2,17 @@
22
* Copyright 2016-2021 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
33
*/
44

5-
val guavaVersion = "28.0-jre"
5+
val guavaVersion = "31.0.1-jre"
66

77
dependencies {
88
compile("com.google.guava:guava:$guavaVersion")
99
}
1010

11+
java {
12+
targetCompatibility = JavaVersion.VERSION_1_8
13+
sourceCompatibility = JavaVersion.VERSION_1_8
14+
}
15+
1116
externalDocumentationLink(
1217
url = "https://google.github.io/guava/releases/$guavaVersion/api/docs/"
1318
)

integration/kotlinx-coroutines-guava/src/ListenableFuture.kt

+4-6
Original file line numberDiff line numberDiff line change
@@ -135,10 +135,8 @@ public fun <T> ListenableFuture<T>.asDeferred(): Deferred<T> {
135135
// Finally, if this isn't done yet, attach a Listener that will complete the Deferred.
136136
val deferred = CompletableDeferred<T>()
137137
Futures.addCallback(this, object : FutureCallback<T> {
138-
override fun onSuccess(result: T?) {
139-
// Here we work with flexible types, so we unchecked cast to trick the type system
140-
@Suppress("UNCHECKED_CAST")
141-
runCatching { deferred.complete(result as T) }
138+
override fun onSuccess(result: T) {
139+
runCatching { deferred.complete(result) }
142140
.onFailure { handleCoroutineException(EmptyCoroutineContext, it) }
143141
}
144142

@@ -351,7 +349,7 @@ private class JobListenableFuture<T>(private val jobToCancel: Job): ListenableFu
351349
*
352350
* To preserve Coroutine's [CancellationException], this future points to either `T` or [Cancelled].
353351
*/
354-
private val auxFuture = SettableFuture.create<Any>()
352+
private val auxFuture = SettableFuture.create<Any?>()
355353

356354
/**
357355
* `true` if [auxFuture.get][ListenableFuture.get] throws [ExecutionException].
@@ -436,7 +434,7 @@ private class JobListenableFuture<T>(private val jobToCancel: Job): ListenableFu
436434
}
437435

438436
/** See [get()]. */
439-
private fun getInternal(result: Any): T = if (result is Cancelled) {
437+
private fun getInternal(result: Any?): T = if (result is Cancelled) {
440438
throw CancellationException().initCause(result.exception)
441439
} else {
442440
// We know that `auxFuture` can contain either `T` or `Cancelled`.

integration/kotlinx-coroutines-slf4j/build.gradle.kts

+4-4
Original file line numberDiff line numberDiff line change
@@ -3,10 +3,10 @@
33
*/
44

55
dependencies {
6-
compile("org.slf4j:slf4j-api:1.7.25")
7-
testCompile("io.github.microutils:kotlin-logging:1.5.4")
8-
testRuntime("ch.qos.logback:logback-classic:1.2.3")
9-
testRuntime("ch.qos.logback:logback-core:1.2.3")
6+
implementation("org.slf4j:slf4j-api:1.7.32")
7+
testImplementation("io.github.microutils:kotlin-logging:2.1.0")
8+
testRuntimeOnly("ch.qos.logback:logback-classic:1.2.7")
9+
testRuntimeOnly("ch.qos.logback:logback-core:1.2.7")
1010
}
1111

1212
externalDocumentationLink(

integration/kotlinx-coroutines-slf4j/src/MDCContext.kt

+1
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,7 @@ public class MDCContext(
4343
/**
4444
* The value of [MDC] context map.
4545
*/
46+
@Suppress("MemberVisibilityCanBePrivate")
4647
public val contextMap: MDCContextMap = MDC.getCopyOfContextMap()
4748
) : ThreadContextElement<MDCContextMap>, AbstractCoroutineContextElement(Key) {
4849
/**

kotlinx-coroutines-core/api/kotlinx-coroutines-core.api

+1
Original file line numberDiff line numberDiff line change
@@ -918,6 +918,7 @@ public final class kotlinx/coroutines/flow/FlowKt {
918918
public static final fun catch (Lkotlinx/coroutines/flow/Flow;Lkotlin/jvm/functions/Function3;)Lkotlinx/coroutines/flow/Flow;
919919
public static final fun channelFlow (Lkotlin/jvm/functions/Function2;)Lkotlinx/coroutines/flow/Flow;
920920
public static final fun collect (Lkotlinx/coroutines/flow/Flow;Lkotlin/coroutines/Continuation;)Ljava/lang/Object;
921+
public static final synthetic fun collect (Lkotlinx/coroutines/flow/Flow;Lkotlin/jvm/functions/Function2;Lkotlin/coroutines/Continuation;)Ljava/lang/Object;
921922
public static final fun collectIndexed (Lkotlinx/coroutines/flow/Flow;Lkotlin/jvm/functions/Function3;Lkotlin/coroutines/Continuation;)Ljava/lang/Object;
922923
public static final fun collectLatest (Lkotlinx/coroutines/flow/Flow;Lkotlin/jvm/functions/Function2;Lkotlin/coroutines/Continuation;)Ljava/lang/Object;
923924
public static final fun combine (Lkotlinx/coroutines/flow/Flow;Lkotlinx/coroutines/flow/Flow;Lkotlin/jvm/functions/Function3;)Lkotlinx/coroutines/flow/Flow;

kotlinx-coroutines-core/build.gradle

+23-2
Original file line numberDiff line numberDiff line change
@@ -185,7 +185,6 @@ kotlin.sourceSets {
185185
jvmTest.dependencies {
186186
api "org.jetbrains.kotlinx:lincheck:$lincheck_version"
187187
api "org.jetbrains.kotlinx:kotlinx-knit-test:$knit_version"
188-
api "com.esotericsoftware:kryo:4.0.0"
189188
implementation project(":android-unit-tests")
190189
}
191190
}
@@ -257,7 +256,7 @@ static void configureJvmForLincheck(task) {
257256
task.minHeapSize = '1g'
258257
task.maxHeapSize = '4g' // we may need more space for building an interleaving tree in the model checking mode
259258
task.jvmArgs = ['--add-opens', 'java.base/jdk.internal.misc=ALL-UNNAMED', // required for transformation
260-
'--add-exports', 'java.base/jdk.internal.util=ALL-UNNAMED'] // in the model checking mode
259+
'--add-exports', 'java.base/jdk.internal.util=ALL-UNNAMED'] // in the model checking mode
261260
task.systemProperty 'kotlinx.coroutines.semaphore.segmentSize', '2'
262261
task.systemProperty 'kotlinx.coroutines.semaphore.maxSpinCycles', '1' // better for the model checking mode
263262
}
@@ -266,6 +265,28 @@ static void configureJvmForLincheck(task) {
266265
task moreTest(dependsOn: [jvmStressTest, jvmLincheckTest])
267266
check.dependsOn moreTest
268267

268+
tasks.jvmLincheckTest {
269+
kover {
270+
enabled = false // Always disabled, lincheck doesn't really support coverage
271+
}
272+
}
273+
274+
def commonKoverExcludes =
275+
["kotlinx.coroutines.test.*", // Deprecated package for removal
276+
"kotlinx.coroutines.debug.*", // Tested by debug module
277+
"kotlinx.coroutines.channels.ChannelsKt__DeprecatedKt.*", // Deprecated
278+
"kotlinx.coroutines.scheduling.LimitingDispatcher", // Deprecated
279+
"kotlinx.coroutines.scheduling.ExperimentalCoroutineDispatcher" // Deprecated
280+
]
281+
282+
tasks.koverHtmlReport {
283+
excludes = commonKoverExcludes
284+
}
285+
286+
tasks.koverVerify {
287+
excludes = commonKoverExcludes
288+
}
289+
269290
task testsJar(type: Jar, dependsOn: jvmTestClasses) {
270291
classifier = 'tests'
271292
from compileTestKotlinJvm.destinationDir

kotlinx-coroutines-core/common/src/CoroutineDispatcher.kt

+2-1
Original file line numberDiff line numberDiff line change
@@ -88,7 +88,8 @@ public abstract class CoroutineDispatcher :
8888
* // At most 1 thread will be doing IO
8989
* private val fileWriterDispatcher = backgroundDispatcher.limitedParallelism(1)
9090
* ```
91-
* is 6. Yet at most 4 coroutines can be executed simultaneously as each view limits only its own parallelism.
91+
* Note how in this example the application has an executor with 4 threads, but the total sum of all limits
92+
* is 6. Still, at most 4 coroutines can be executed simultaneously as each view limits only its own parallelism.
9293
*
9394
* Note that this example was structured in such a way that it illustrates the parallelism guarantees.
9495
* In practice, it is usually better to use [Dispatchers.IO] or [Dispatchers.Default] instead of creating a

0 commit comments

Comments
 (0)