From 9042a4a8f67a27c463f9d125e677ad0ec3e9ddfd Mon Sep 17 00:00:00 2001 From: Roman Elizarov Date: Tue, 11 Sep 2018 18:42:03 +0300 Subject: [PATCH 1/3] Dispatchers are renamed and grouped in the Dispatchers object MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * Dispatchers.Default — a default dispatcher for background asynchronous tasks (currently backed by FJP commonPool, a new dispatcher in the future). * Dispatchers.IO — a dispatcher for blocking background operations (#79). * Dispatchers.Main — a dispatcher for Android Main Thread (#533). * Dispatchers.Swing — a dispatcher for Swing Event Dispatch Thread. * Dispatchers.JavaFx — a dispatcher for JavaFx Application Thread. * Old dispatchers are deprecated, CommonPool is deprecated, too. * awaitPulse() in JavaFx and awaitFrame() in Android are top-level funs. * Introduced HandlerDispatcher, SwingDispatcher, and JavaFxDispatcher types in the corresponding UI modules for type-safety and future extensions Fixes #41 Fixes #533 --- .../kotlinx-coroutines-android.txt | 19 +- .../kotlinx-coroutines-core.txt | 12 +- .../kotlinx-coroutines-javafx.txt | 13 +- .../kotlinx-coroutines-swing.txt | 12 +- .../src/Builders.common.kt | 14 +- .../src/CoroutineContext.common.kt | 6 + .../src/CoroutineDispatcher.kt | 13 +- .../src/CoroutineScope.kt | 4 +- .../src/CoroutineStart.kt | 6 +- .../src/Deferred.kt | 13 +- .../src/Dispatchers.common.kt | 48 +++++ .../src/Unconfined.kt | 17 +- .../src/Yield.kt | 2 +- .../src/channels/Broadcast.kt | 18 +- .../src/channels/Channels.common.kt | 34 ++-- .../src/channels/Produce.kt | 13 +- .../channels/ArrayBroadcastChannelTest.kt | 4 +- .../channels/ConflatedBroadcastChannelTest.kt | 4 +- .../test/channels/ProduceTest.kt | 2 +- .../test/sync/MutexTest.kt | 2 +- core/kotlinx-coroutines-core/README.md | 2 - .../kotlinx-coroutines-core/src/CommonPool.kt | 6 + .../src/CoroutineContext.kt | 46 +++-- .../src/DefaultExecutor.kt | 3 +- .../src/Dispatchers.kt | 23 +++ .../src/channels/Actor.kt | 13 +- .../src/channels/TickerChannels.kt | 4 +- .../ExperimentalCoroutineDispatcher.kt | 5 +- .../test/DebugThreadNameTest.kt | 2 +- .../test/IODispatcherTest.kt | 2 +- .../test/ThreadContextElementTest.kt | 2 +- .../test/WithDefaultContextTest.kt | 4 +- .../channels/BroadcastChannelSubStressTest.kt | 2 +- .../channels/ChannelSendReceiveStressTest.kt | 4 +- ...nflatedBroadcastChannelNotifyStressTest.kt | 4 +- .../test/channels/SimpleSendReceiveJvmTest.kt | 2 +- .../test/guide/example-cancel-02.kt | 2 +- .../test/guide/example-cancel-03.kt | 2 +- .../test/guide/example-context-01.kt | 6 +- .../test/guide/example-context-02.kt | 2 +- .../test/guide/example-context-09.kt | 2 +- .../test/guide/example-context-10.kt | 2 +- .../test/guide/example-context-11.kt | 2 +- .../test/guide/example-sync-01b.kt | 2 +- .../test/guide/test/GuideTest.kt | 2 +- coroutines-guide.md | 50 +++--- .../src/ListenableFuture.kt | 15 +- .../test/ListenableFutureTest.kt | 4 +- .../src/channels8/Channels.kt | 4 +- .../src/future/Future.kt | 22 +-- .../test/MDCContextTest.kt | 4 +- js/kotlinx-coroutines-core-js/README.md | 1 - .../src/CoroutineContext.kt | 22 ++- js/kotlinx-coroutines-core-js/src/Promise.kt | 10 +- .../kotlinx-coroutines-core-native/README.md | 1 - .../src/CoroutineContext.kt | 15 +- reactive/coroutines-guide-reactive.md | 21 ++- .../src/Convert.kt | 2 +- .../src/Publish.kt | 4 +- .../test/IntegrationTest.kt | 4 +- .../test/PublisherCompletionStressTest.kt | 2 +- .../test/PublisherMultiTest.kt | 2 +- .../kotlinx-coroutines-reactor/src/Convert.kt | 6 +- .../kotlinx-coroutines-reactor/src/Flux.kt | 24 +-- .../kotlinx-coroutines-reactor/src/Mono.kt | 9 +- .../test/ConvertTest.kt | 18 +- .../test/FluxCompletionStressTest.kt | 2 +- .../test/FluxMultiTest.kt | 2 +- .../src/RxCompletable.kt | 6 +- .../src/RxObservable.kt | 4 +- .../kotlinx-coroutines-rx1/src/RxSingle.kt | 4 +- .../test/ConvertTest.kt | 14 +- .../test/IntegrationTest.kt | 6 +- .../test/ObservableCompletionStressTest.kt | 2 +- .../test/ObservableMultiTest.kt | 4 +- .../src/RxCompletable.kt | 4 +- .../kotlinx-coroutines-rx2/src/RxFlowable.kt | 4 +- .../kotlinx-coroutines-rx2/src/RxMaybe.kt | 4 +- .../src/RxObservable.kt | 4 +- .../kotlinx-coroutines-rx2/src/RxSingle.kt | 4 +- .../test/ConvertTest.kt | 26 +-- .../test/IntegrationTest.kt | 4 +- .../test/ObservableCompletionStressTest.kt | 2 +- .../test/ObservableMultiTest.kt | 2 +- .../test/guide/example-reactive-basic-01.kt | 1 + .../test/guide/example-reactive-basic-02.kt | 1 + .../test/guide/example-reactive-basic-05.kt | 1 + .../test/guide/example-reactive-basic-07.kt | 2 +- .../test/guide/example-reactive-basic-08.kt | 1 + .../test/guide/example-reactive-basic-09.kt | 3 +- .../test/guide/example-reactive-context-02.kt | 2 +- .../test/guide/example-reactive-context-03.kt | 4 +- .../test/guide/example-reactive-context-05.kt | 2 +- .../guide/example-reactive-operators-01.kt | 6 +- .../guide/example-reactive-operators-03.kt | 2 +- ui/coroutines-guide-ui.md | 82 ++++----- .../src/HandlerContext.kt | 115 ------------ .../src/HandlerDispatcher.kt | 164 ++++++++++++++++++ .../src/{JavaFx.kt => JavaFxDispatcher.kt} | 80 ++++++--- .../test/JavaFxTest.kt | 2 +- .../test/examples/FxExampleApp.kt | 6 +- .../test/guide/example-ui-actor-01.kt | 4 +- .../test/guide/example-ui-actor-02.kt | 4 +- .../test/guide/example-ui-actor-03.kt | 4 +- .../test/guide/example-ui-advanced-01.kt | 4 +- .../test/guide/example-ui-advanced-02.kt | 4 +- .../test/guide/example-ui-basic-01.kt | 2 +- .../test/guide/example-ui-basic-02.kt | 4 +- .../test/guide/example-ui-basic-03.kt | 4 +- .../test/guide/example-ui-blocking-01.kt | 6 +- .../test/guide/example-ui-blocking-02.kt | 8 +- .../test/guide/example-ui-blocking-03.kt | 8 +- .../src/{Swing.kt => SwingDispatcher.kt} | 36 ++-- ui/kotlinx-coroutines-swing/test/SwingTest.kt | 7 +- .../test/examples/SwingExampleApp.kt | 2 +- .../test/examples/swing-example.kt | 12 +- 116 files changed, 782 insertions(+), 541 deletions(-) create mode 100644 common/kotlinx-coroutines-core-common/src/Dispatchers.common.kt create mode 100644 core/kotlinx-coroutines-core/src/Dispatchers.kt delete mode 100644 ui/kotlinx-coroutines-android/src/HandlerContext.kt create mode 100644 ui/kotlinx-coroutines-android/src/HandlerDispatcher.kt rename ui/kotlinx-coroutines-javafx/src/{JavaFx.kt => JavaFxDispatcher.kt} (53%) rename ui/kotlinx-coroutines-swing/src/{Swing.kt => SwingDispatcher.kt} (59%) diff --git a/binary-compatibility-validator/reference-public-api/kotlinx-coroutines-android.txt b/binary-compatibility-validator/reference-public-api/kotlinx-coroutines-android.txt index cc39394c7d..41843a6be6 100644 --- a/binary-compatibility-validator/reference-public-api/kotlinx-coroutines-android.txt +++ b/binary-compatibility-validator/reference-public-api/kotlinx-coroutines-android.txt @@ -3,14 +3,14 @@ public final class kotlinx/coroutines/experimental/android/AndroidExceptionPreHa public fun handleException (Lkotlin/coroutines/experimental/CoroutineContext;Ljava/lang/Throwable;)V } -public final class kotlinx/coroutines/experimental/android/HandlerContext : kotlinx/coroutines/experimental/CoroutineDispatcher, kotlinx/coroutines/experimental/Delay { +public final class kotlinx/coroutines/experimental/android/HandlerContext : kotlinx/coroutines/experimental/android/HandlerDispatcher, kotlinx/coroutines/experimental/Delay { public fun (Landroid/os/Handler;Ljava/lang/String;)V public synthetic fun (Landroid/os/Handler;Ljava/lang/String;ILkotlin/jvm/internal/DefaultConstructorMarker;)V public final fun awaitFrame (Lkotlin/coroutines/experimental/Continuation;)Ljava/lang/Object; - public fun delay (JLjava/util/concurrent/TimeUnit;Lkotlin/coroutines/experimental/Continuation;)Ljava/lang/Object; public fun dispatch (Lkotlin/coroutines/experimental/CoroutineContext;Ljava/lang/Runnable;)V public fun equals (Ljava/lang/Object;)Z - public final fun getImmediate ()Lkotlinx/coroutines/experimental/android/HandlerContext; + public fun getImmediate ()Lkotlinx/coroutines/experimental/android/HandlerContext; + public synthetic fun getImmediate ()Lkotlinx/coroutines/experimental/android/HandlerDispatcher; public fun hashCode ()I public fun invokeOnTimeout (JLjava/util/concurrent/TimeUnit;Ljava/lang/Runnable;)Lkotlinx/coroutines/experimental/DisposableHandle; public fun isDispatchNeeded (Lkotlin/coroutines/experimental/CoroutineContext;)Z @@ -18,8 +18,17 @@ public final class kotlinx/coroutines/experimental/android/HandlerContext : kotl public fun toString ()Ljava/lang/String; } -public final class kotlinx/coroutines/experimental/android/HandlerContextKt { - public static final fun asCoroutineDispatcher (Landroid/os/Handler;)Lkotlinx/coroutines/experimental/android/HandlerContext; +public abstract class kotlinx/coroutines/experimental/android/HandlerDispatcher : kotlinx/coroutines/experimental/CoroutineDispatcher, kotlinx/coroutines/experimental/Delay { + public fun delay (JLjava/util/concurrent/TimeUnit;Lkotlin/coroutines/experimental/Continuation;)Ljava/lang/Object; + public abstract fun getImmediate ()Lkotlinx/coroutines/experimental/android/HandlerDispatcher; + public fun invokeOnTimeout (JLjava/util/concurrent/TimeUnit;Ljava/lang/Runnable;)Lkotlinx/coroutines/experimental/DisposableHandle; +} + +public final class kotlinx/coroutines/experimental/android/HandlerDispatcherKt { + public static final synthetic fun asCoroutineDispatcher (Landroid/os/Handler;)Lkotlinx/coroutines/experimental/android/HandlerContext; + public static final fun asCoroutineDispatcher (Landroid/os/Handler;)Lkotlinx/coroutines/experimental/android/HandlerDispatcher; + public static final fun awaitFrame (Lkotlin/coroutines/experimental/Continuation;)Ljava/lang/Object; + public static final fun getMain (Lkotlinx/coroutines/experimental/Dispatchers;)Lkotlinx/coroutines/experimental/android/HandlerDispatcher; public static final fun getUI ()Lkotlinx/coroutines/experimental/android/HandlerContext; } diff --git a/binary-compatibility-validator/reference-public-api/kotlinx-coroutines-core.txt b/binary-compatibility-validator/reference-public-api/kotlinx-coroutines-core.txt index 0a7848fe7e..f95bce0ebf 100644 --- a/binary-compatibility-validator/reference-public-api/kotlinx-coroutines-core.txt +++ b/binary-compatibility-validator/reference-public-api/kotlinx-coroutines-core.txt @@ -139,7 +139,6 @@ public final class kotlinx/coroutines/experimental/CoroutineContextKt { public static final field DEBUG_PROPERTY_VALUE_AUTO Ljava/lang/String; public static final field DEBUG_PROPERTY_VALUE_OFF Ljava/lang/String; public static final field DEBUG_PROPERTY_VALUE_ON Ljava/lang/String; - public static final field IO_PARALLELISM_PROPERTY_NAME Ljava/lang/String; public static final fun getDefaultDispatcher ()Lkotlinx/coroutines/experimental/CoroutineDispatcher; public static final fun getIO ()Lkotlinx/coroutines/experimental/CoroutineDispatcher; public static final fun newCoroutineContext (Lkotlin/coroutines/experimental/CoroutineContext;)Lkotlin/coroutines/experimental/CoroutineContext; @@ -297,6 +296,17 @@ public final class kotlinx/coroutines/experimental/DispatchedTask$DefaultImpls { public static fun run (Lkotlinx/coroutines/experimental/DispatchedTask;)V } +public final class kotlinx/coroutines/experimental/Dispatchers { + public static final field Default Lkotlinx/coroutines/experimental/CoroutineDispatcher; + public static final field INSTANCE Lkotlinx/coroutines/experimental/Dispatchers; + public static final field Unconfined Lkotlinx/coroutines/experimental/CoroutineDispatcher; +} + +public final class kotlinx/coroutines/experimental/DispatchersKt { + public static final field IO_PARALLELISM_PROPERTY_NAME Ljava/lang/String; + public static final fun getIO (Lkotlinx/coroutines/experimental/Dispatchers;)Lkotlinx/coroutines/experimental/CoroutineDispatcher; +} + public abstract interface class kotlinx/coroutines/experimental/DisposableHandle { public abstract fun dispose ()V } diff --git a/binary-compatibility-validator/reference-public-api/kotlinx-coroutines-javafx.txt b/binary-compatibility-validator/reference-public-api/kotlinx-coroutines-javafx.txt index aa1216f257..06955a44e3 100644 --- a/binary-compatibility-validator/reference-public-api/kotlinx-coroutines-javafx.txt +++ b/binary-compatibility-validator/reference-public-api/kotlinx-coroutines-javafx.txt @@ -1,10 +1,19 @@ -public final class kotlinx/coroutines/experimental/javafx/JavaFx : kotlinx/coroutines/experimental/CoroutineDispatcher, kotlinx/coroutines/experimental/Delay { +public final class kotlinx/coroutines/experimental/javafx/JavaFx : kotlinx/coroutines/experimental/javafx/JavaFxDispatcher, kotlinx/coroutines/experimental/Delay { public static final field INSTANCE Lkotlinx/coroutines/experimental/javafx/JavaFx; public final fun awaitPulse (Lkotlin/coroutines/experimental/Continuation;)Ljava/lang/Object; - public fun delay (JLjava/util/concurrent/TimeUnit;Lkotlin/coroutines/experimental/Continuation;)Ljava/lang/Object; public fun dispatch (Lkotlin/coroutines/experimental/CoroutineContext;Ljava/lang/Runnable;)V public fun invokeOnTimeout (JLjava/util/concurrent/TimeUnit;Ljava/lang/Runnable;)Lkotlinx/coroutines/experimental/DisposableHandle; public fun scheduleResumeAfterDelay (JLjava/util/concurrent/TimeUnit;Lkotlinx/coroutines/experimental/CancellableContinuation;)V public fun toString ()Ljava/lang/String; } +public abstract class kotlinx/coroutines/experimental/javafx/JavaFxDispatcher : kotlinx/coroutines/experimental/CoroutineDispatcher, kotlinx/coroutines/experimental/Delay { + public fun delay (JLjava/util/concurrent/TimeUnit;Lkotlin/coroutines/experimental/Continuation;)Ljava/lang/Object; + public fun invokeOnTimeout (JLjava/util/concurrent/TimeUnit;Ljava/lang/Runnable;)Lkotlinx/coroutines/experimental/DisposableHandle; +} + +public final class kotlinx/coroutines/experimental/javafx/JavaFxDispatcherKt { + public static final fun awaitPulse (Lkotlin/coroutines/experimental/Continuation;)Ljava/lang/Object; + public static final fun getJavaFx (Lkotlinx/coroutines/experimental/Dispatchers;)Lkotlinx/coroutines/experimental/javafx/JavaFxDispatcher; +} + diff --git a/binary-compatibility-validator/reference-public-api/kotlinx-coroutines-swing.txt b/binary-compatibility-validator/reference-public-api/kotlinx-coroutines-swing.txt index f41c663b95..1a7f44d73b 100644 --- a/binary-compatibility-validator/reference-public-api/kotlinx-coroutines-swing.txt +++ b/binary-compatibility-validator/reference-public-api/kotlinx-coroutines-swing.txt @@ -1,9 +1,17 @@ -public final class kotlinx/coroutines/experimental/swing/Swing : kotlinx/coroutines/experimental/CoroutineDispatcher, kotlinx/coroutines/experimental/Delay { +public final class kotlinx/coroutines/experimental/swing/Swing : kotlinx/coroutines/experimental/swing/SwingDispatcher, kotlinx/coroutines/experimental/Delay { public static final field INSTANCE Lkotlinx/coroutines/experimental/swing/Swing; - public fun delay (JLjava/util/concurrent/TimeUnit;Lkotlin/coroutines/experimental/Continuation;)Ljava/lang/Object; public fun dispatch (Lkotlin/coroutines/experimental/CoroutineContext;Ljava/lang/Runnable;)V public fun invokeOnTimeout (JLjava/util/concurrent/TimeUnit;Ljava/lang/Runnable;)Lkotlinx/coroutines/experimental/DisposableHandle; public fun scheduleResumeAfterDelay (JLjava/util/concurrent/TimeUnit;Lkotlinx/coroutines/experimental/CancellableContinuation;)V public fun toString ()Ljava/lang/String; } +public abstract class kotlinx/coroutines/experimental/swing/SwingDispatcher : kotlinx/coroutines/experimental/CoroutineDispatcher, kotlinx/coroutines/experimental/Delay { + public fun delay (JLjava/util/concurrent/TimeUnit;Lkotlin/coroutines/experimental/Continuation;)Ljava/lang/Object; + public fun invokeOnTimeout (JLjava/util/concurrent/TimeUnit;Ljava/lang/Runnable;)Lkotlinx/coroutines/experimental/DisposableHandle; +} + +public final class kotlinx/coroutines/experimental/swing/SwingDispatcherKt { + public static final fun getSwing (Lkotlinx/coroutines/experimental/Dispatchers;)Lkotlinx/coroutines/experimental/swing/SwingDispatcher; +} + diff --git a/common/kotlinx-coroutines-core-common/src/Builders.common.kt b/common/kotlinx-coroutines-core-common/src/Builders.common.kt index ebc63adf90..4bfba1d517 100644 --- a/common/kotlinx-coroutines-core-common/src/Builders.common.kt +++ b/common/kotlinx-coroutines-core-common/src/Builders.common.kt @@ -19,7 +19,7 @@ import kotlin.coroutines.experimental.intrinsics.* * The coroutine is cancelled when the resulting job is [cancelled][Job.cancel]. * * Coroutine context is inherited from a [CoroutineScope], additional context elements can be specified with [context] argument. - * If the context does not have any dispatcher nor any other [ContinuationInterceptor], then [DefaultDispatcher] is used. + * If the context does not have any dispatcher nor any other [ContinuationInterceptor], then [Dispatchers.Default] is used. * The parent job is inherited from a [CoroutineScope] as well, but it can also be overridden * with corresponding [coroutineContext] element. * @@ -35,10 +35,10 @@ import kotlin.coroutines.experimental.intrinsics.* * * See [newCoroutineContext] for a description of debugging facilities that are available for newly created coroutine. * - * @param context additional to [CoroutineScope.coroutineContext] context of the coroutine + * @param context additional to [CoroutineScope.coroutineContext] context of the coroutine. * @param start coroutine start option. The default value is [CoroutineStart.DEFAULT]. * @param onCompletion optional completion handler for the coroutine (see [Job.invokeOnCompletion]). - * @param block the coroutine code which will be invoked in the context of the provided scope + * @param block the coroutine code which will be invoked in the context of the provided scope. **/ public fun CoroutineScope.launch( context: CoroutineContext = EmptyCoroutineContext, @@ -64,7 +64,7 @@ public fun CoroutineScope.launch( replaceWith = ReplaceWith("GlobalScope.launch(context, start, onCompletion, block)", imports = ["kotlinx.coroutines.experimental.*"]) ) public fun launch( - context: CoroutineContext = DefaultDispatcher, + context: CoroutineContext = Dispatchers.Default, start: CoroutineStart = CoroutineStart.DEFAULT, onCompletion: CompletionHandler? = null, block: suspend CoroutineScope.() -> Unit @@ -80,7 +80,7 @@ public fun launch( replaceWith = ReplaceWith("GlobalScope.launch(context + parent, start, onCompletion, block)", imports = ["kotlinx.coroutines.experimental.*"]) ) public fun launch( - context: CoroutineContext = DefaultDispatcher, + context: CoroutineContext = Dispatchers.Default, start: CoroutineStart = CoroutineStart.DEFAULT, parent: Job? = null, // nullable for binary compatibility onCompletion: CompletionHandler? = null, @@ -91,7 +91,7 @@ public fun launch( /** @suppress **Deprecated**: Binary compatibility */ @Deprecated(message = "Binary compatibility", level = DeprecationLevel.HIDDEN) public fun launch( - context: CoroutineContext = DefaultDispatcher, + context: CoroutineContext = Dispatchers.Default, start: CoroutineStart = CoroutineStart.DEFAULT, parent: Job? = null, block: suspend CoroutineScope.() -> Unit @@ -101,7 +101,7 @@ public fun launch( /** @suppress **Deprecated**: Binary compatibility */ @Deprecated(message = "Binary compatibility", level = DeprecationLevel.HIDDEN) public fun launch( - context: CoroutineContext = DefaultDispatcher, + context: CoroutineContext = Dispatchers.Default, start: CoroutineStart = CoroutineStart.DEFAULT, block: suspend CoroutineScope.() -> Unit ): Job = diff --git a/common/kotlinx-coroutines-core-common/src/CoroutineContext.common.kt b/common/kotlinx-coroutines-core-common/src/CoroutineContext.common.kt index 4cac79c489..5eed6c18e1 100644 --- a/common/kotlinx-coroutines-core-common/src/CoroutineContext.common.kt +++ b/common/kotlinx-coroutines-core-common/src/CoroutineContext.common.kt @@ -9,8 +9,14 @@ import kotlin.coroutines.experimental.* public expect fun CoroutineScope.newCoroutineContext(context: CoroutineContext): CoroutineContext @Suppress("PropertyName") +@Deprecated( + message = "Use Dispatchers.Default", + replaceWith = ReplaceWith("Dispatchers.Default", + imports = ["kotlinx.coroutines.experimental.Dispatchers"])) public expect val DefaultDispatcher: CoroutineDispatcher +internal expect fun createDefaultDispatcher(): CoroutineDispatcher + @Suppress("PropertyName") internal expect val DefaultDelay: Delay diff --git a/common/kotlinx-coroutines-core-common/src/CoroutineDispatcher.kt b/common/kotlinx-coroutines-core-common/src/CoroutineDispatcher.kt index 805dc6568b..296f8f8a2a 100644 --- a/common/kotlinx-coroutines-core-common/src/CoroutineDispatcher.kt +++ b/common/kotlinx-coroutines-core-common/src/CoroutineDispatcher.kt @@ -9,16 +9,15 @@ import kotlin.coroutines.experimental.* /** * Base class that shall be extended by all coroutine dispatcher implementations. * - * The following standard implementations are provided by `kotlinx.coroutines`: + * The following standard implementations are provided by `kotlinx.coroutines` as properties on + * [Dispatchers] objects: * - * * [DefaultDispatcher] -- is used by all standard builder if no dispatcher nor any other [ContinuationInterceptor] - * is specified in their context. It is currently equal to [CommonPool] (subject to change in the future). + * * [Dispatchers.Default] -- is used by all standard builder if no dispatcher nor any other [ContinuationInterceptor] + * is specified in their context. It uses a common pool of shared background threads. * This is an appropriate choice for compute-intensive coroutines that consume CPU resources. - * * [CommonPool] -- schedules coroutine execution to a common pool of shared background threads designed - * to be used for compute-intensive code. - * * [IO] -- uses a shared pool of on-demand created threads and is designed for offloading of IO-intensive _blocking_ + * * [Dispatchers.IO] -- uses a shared pool of on-demand created threads and is designed for offloading of IO-intensive _blocking_ * operations (like file I/O and blocking socket I/O). - * * [Unconfined] -- starts coroutine execution in the current call-frame until the first suspension. + * * [Dispatchers.Unconfined] -- starts coroutine execution in the current call-frame until the first suspension. * On first suspension the coroutine builder function returns. * The coroutine resumes in whatever thread that is used by the * corresponding suspending function, without confining it to any specific thread or pool. diff --git a/common/kotlinx-coroutines-core-common/src/CoroutineScope.kt b/common/kotlinx-coroutines-core-common/src/CoroutineScope.kt index 649e31641c..b15dca70b9 100644 --- a/common/kotlinx-coroutines-core-common/src/CoroutineScope.kt +++ b/common/kotlinx-coroutines-core-common/src/CoroutineScope.kt @@ -111,7 +111,7 @@ public val CoroutineScope.isActive: Boolean * * Global scope is used to launch top-level coroutines which are operating on the whole application lifetime * and are not cancelled prematurely. - * Another use of the global scope is [Unconfined] operators, which don't have any job associated with them. + * Another use of the global scope is operators running in [Dispatchers.Unconfined], which don't have any job associated with them. * * Application code usually should use application-defined [CoroutineScope], using * [async][CoroutineScope.async] or [launch][CoroutineScope.launch] @@ -120,7 +120,7 @@ public val CoroutineScope.isActive: Boolean * Usage of this interface may look like this: * * ``` - * fun ReceiveChannel.sqrt(): ReceiveChannel = GlobalScope.produce(Unconfined) { + * fun ReceiveChannel.sqrt(): ReceiveChannel = GlobalScope.produce(Dispatchers.Unconfined) { * for (number in this) { * send(Math.sqrt(number)) * } diff --git a/common/kotlinx-coroutines-core-common/src/CoroutineStart.kt b/common/kotlinx-coroutines-core-common/src/CoroutineStart.kt index 1a99718ecf..e91aea38a3 100644 --- a/common/kotlinx-coroutines-core-common/src/CoroutineStart.kt +++ b/common/kotlinx-coroutines-core-common/src/CoroutineStart.kt @@ -26,8 +26,8 @@ public enum class CoroutineStart { * function as most dispatchers do, then the coroutine code is dispatched for execution later, while the code that * invoked the coroutine builder continues execution. * - * Note, that [Unconfined] dispatcher always returns `false` from its [CoroutineDispatcher.isDispatchNeeded] - * function, so starting coroutine with [Unconfined] dispatcher by [DEFAULT] is the same as using [UNDISPATCHED]. + * Note, that [Dispatchers.Unconfined] always returns `false` from its [CoroutineDispatcher.isDispatchNeeded] + * function, so starting coroutine with [Dispatchers.Unconfined] by [DEFAULT] is the same as using [UNDISPATCHED]. * * If coroutine [Job] is cancelled before it even had a chance to start executing, then it will not start its * execution at all, but will complete with an exception. @@ -59,7 +59,7 @@ public enum class CoroutineStart { /** * Immediately executes coroutine until its first suspension point _in the current thread_ as if the - * coroutine was started using [Unconfined] dispatcher. However, when coroutine is resumed from suspension + * coroutine was started using [Dispatchers.Unconfined]. However, when coroutine is resumed from suspension * it is dispatched according to the [CoroutineDispatcher] in its context. * * This is similar to [ATOMIC] in the sense that coroutine starts executing even if it was already cancelled, diff --git a/common/kotlinx-coroutines-core-common/src/Deferred.kt b/common/kotlinx-coroutines-core-common/src/Deferred.kt index 32665400c0..cfc2ec36ac 100644 --- a/common/kotlinx-coroutines-core-common/src/Deferred.kt +++ b/common/kotlinx-coroutines-core-common/src/Deferred.kt @@ -4,7 +4,6 @@ package kotlinx.coroutines.experimental -import kotlinx.coroutines.experimental.internal.* import kotlinx.coroutines.experimental.intrinsics.* import kotlinx.coroutines.experimental.selects.* import kotlin.coroutines.experimental.* @@ -128,7 +127,7 @@ public interface Deferred : Job { * The running coroutine is cancelled when the resulting deferred is [cancelled][Job.cancel]. * * Coroutine context is inherited from a [CoroutineScope], additional context elements can be specified with [context] argument. - * If the context does not have any dispatcher nor any other [ContinuationInterceptor], then [DefaultDispatcher] is used. + * If the context does not have any dispatcher nor any other [ContinuationInterceptor], then [Dispatchers.Default] is used. * The parent job is inherited from a [CoroutineScope] as well, but it can also be overridden * with corresponding [coroutineContext] element. * @@ -138,7 +137,7 @@ public interface Deferred : Job { * the resulting [Deferred] is created in _new_ state. It can be explicitly started with [start][Job.start] * function and will be started implicitly on the first invocation of [join][Job.join], [await][Deferred.await] or [awaitAll]. * - * @param context additional to [CoroutineScope.coroutineContext] context of the coroutine + * @param context additional to [CoroutineScope.coroutineContext] context of the coroutine. * @param start coroutine start option. The default value is [CoroutineStart.DEFAULT]. * @param onCompletion optional completion handler for the coroutine (see [Job.invokeOnCompletion]). * @param block the coroutine code. @@ -167,7 +166,7 @@ public fun CoroutineScope.async( replaceWith = ReplaceWith("GlobalScope.async(context, start, onCompletion, block)", imports = ["kotlinx.coroutines.experimental.*"]) ) public fun async( - context: CoroutineContext = DefaultDispatcher, + context: CoroutineContext = Dispatchers.Default, start: CoroutineStart = CoroutineStart.DEFAULT, onCompletion: CompletionHandler? = null, block: suspend CoroutineScope.() -> T @@ -183,7 +182,7 @@ public fun async( replaceWith = ReplaceWith("GlobalScope.async(context + parent, start, onCompletion, block)", imports = ["kotlinx.coroutines.experimental.*"]) ) public fun async( - context: CoroutineContext = DefaultDispatcher, + context: CoroutineContext = Dispatchers.Default, start: CoroutineStart = CoroutineStart.DEFAULT, parent: Job? = null, onCompletion: CompletionHandler? = null, @@ -194,7 +193,7 @@ public fun async( /** @suppress **Deprecated**: Binary compatibility */ @Deprecated(message = "Binary compatibility", level = DeprecationLevel.HIDDEN) public fun async( - context: CoroutineContext = DefaultDispatcher, + context: CoroutineContext = Dispatchers.Default, start: CoroutineStart = CoroutineStart.DEFAULT, parent: Job? = null, block: suspend CoroutineScope.() -> T @@ -204,7 +203,7 @@ public fun async( /** @suppress **Deprecated**: Binary compatibility */ @Deprecated(message = "Binary compatibility", level = DeprecationLevel.HIDDEN) public fun async( - context: CoroutineContext = DefaultDispatcher, + context: CoroutineContext = Dispatchers.Default, start: CoroutineStart = CoroutineStart.DEFAULT, block: suspend CoroutineScope.() -> T ): Deferred = diff --git a/common/kotlinx-coroutines-core-common/src/Dispatchers.common.kt b/common/kotlinx-coroutines-core-common/src/Dispatchers.common.kt new file mode 100644 index 0000000000..6528c2b597 --- /dev/null +++ b/common/kotlinx-coroutines-core-common/src/Dispatchers.common.kt @@ -0,0 +1,48 @@ +/* + * Copyright 2016-2018 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license. + */ + +/* + * Copyright 2016-2018 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license. + */ + +package kotlinx.coroutines.experimental + +import kotlinx.coroutines.experimental.internal.* +import kotlin.coroutines.experimental.* + +/** + * Groups various implementations of [CoroutineDispatcher]. + */ +public object Dispatchers { + /** + * The default [CoroutineDispatcher] that is used by all standard builders like + * [launch][CoroutineScope.launch], [async][CoroutineScope.async], etc + * if no dispatcher nor any other [ContinuationInterceptor] is specified in their context. + * + * It is backed by a shared pool of threads on JVM. + * You can set system property "`kotlinx.coroutines.scheduler`" (either no value or to the value of "`on`") + * to use an experimental coroutine dispatcher that shares threads with [Dispatchers.IO] and thus can switch to + * to context without performing an actual thread context switch. + */ + @JvmField + public val Default: CoroutineDispatcher = + createDefaultDispatcher() + + /** + * A coroutine dispatcher that is not confined to any specific thread. + * It executes initial continuation of the coroutine _immediately_ in the current call-frame + * and lets the coroutine resume in whatever thread that is used by the corresponding suspending function, without + * mandating any specific threading policy. + * **Note: use with extreme caution, not for general code**. + * + * Note, that if you need your coroutine to be confined to a particular thread or a thread-pool after resumption, + * but still want to execute it in the current call-frame until its first suspension, then you can use + * an optional [CoroutineStart] parameter in coroutine builders like + * [launch][CoroutineScope.launch] and [async][CoroutineScope.async] setting it to the + * the value of [CoroutineStart.UNDISPATCHED]. + */ + @JvmField + public val Unconfined: CoroutineDispatcher = + kotlinx.coroutines.experimental.Unconfined +} \ No newline at end of file diff --git a/common/kotlinx-coroutines-core-common/src/Unconfined.kt b/common/kotlinx-coroutines-core-common/src/Unconfined.kt index 1bbf115eeb..fda0c0fb6a 100644 --- a/common/kotlinx-coroutines-core-common/src/Unconfined.kt +++ b/common/kotlinx-coroutines-core-common/src/Unconfined.kt @@ -8,17 +8,14 @@ import kotlin.coroutines.experimental.* /** * A coroutine dispatcher that is not confined to any specific thread. - * It executes initial continuation of the coroutine _right here_ in the current call-frame - * and let the coroutine resume in whatever thread that is used by the corresponding suspending function, without - * mandating any specific threading policy. - * **Note: use with extreme caution, not for general code**. - * - * Note, that if you need your coroutine to be confined to a particular thread or a thread-pool after resumption, - * but still want to execute it in the current call-frame until its first suspension, then you can use - * an optional [CoroutineStart] parameter in coroutine builders like - * [launch][CoroutineScope.launch] and [async][CoroutineScope.async] setting it to the - * the value of [CoroutineStart.UNDISPATCHED]. + * @suppress **Deprecated**: Use [Dispatchers.Unconfined]. */ +@Deprecated( + message = "Use Dispatchers.Unconfined", + replaceWith = ReplaceWith("Dispatchers.Unconfined", + imports = ["kotlinx.coroutines.experimental.Dispatchers"]) +) +// todo: This will become an internal implementation object public object Unconfined : CoroutineDispatcher() { override fun isDispatchNeeded(context: CoroutineContext): Boolean = false override fun dispatch(context: CoroutineContext, block: Runnable) { throw UnsupportedOperationException() } diff --git a/common/kotlinx-coroutines-core-common/src/Yield.kt b/common/kotlinx-coroutines-core-common/src/Yield.kt index e9903a8390..f0d3de2802 100644 --- a/common/kotlinx-coroutines-core-common/src/Yield.kt +++ b/common/kotlinx-coroutines-core-common/src/Yield.kt @@ -9,7 +9,7 @@ import kotlin.coroutines.experimental.intrinsics.* /** * Yields a thread (or thread pool) of the current coroutine dispatcher to other coroutines to run. - * If the coroutine dispatcher does not have its own thread pool (like [Unconfined] dispatcher) then this + * If the coroutine dispatcher does not have its own thread pool (like [Dispatchers.Unconfined]) then this * function does nothing, but checks if the coroutine [Job] was completed. * This suspending function is cancellable. * If the [Job] of the current coroutine is cancelled or completed when this suspending function is invoked or while diff --git a/common/kotlinx-coroutines-core-common/src/channels/Broadcast.kt b/common/kotlinx-coroutines-core-common/src/channels/Broadcast.kt index 009cccc825..097816d358 100644 --- a/common/kotlinx-coroutines-core-common/src/channels/Broadcast.kt +++ b/common/kotlinx-coroutines-core-common/src/channels/Broadcast.kt @@ -19,8 +19,8 @@ import kotlin.coroutines.experimental.* fun ReceiveChannel.broadcast( capacity: Int = 1, start: CoroutineStart = CoroutineStart.LAZY -) : BroadcastChannel = - GlobalScope.broadcast(Unconfined, capacity = capacity, start = start, onCompletion = consumes()) { +): BroadcastChannel = + GlobalScope.broadcast(Dispatchers.Unconfined, capacity = capacity, start = start, onCompletion = consumes()) { for (e in this@broadcast) { send(e) } @@ -32,18 +32,20 @@ fun ReceiveChannel.broadcast( */ @Deprecated( message = "Standalone coroutine builders are deprecated, use extensions on CoroutineScope instead", - replaceWith = ReplaceWith("GlobalScope.broadcast(context + parent, capacity, start, onCompletion, block)", - imports = ["kotlinx.coroutines.experimental.GlobalScope", "kotlinx.coroutines.experimental.channels.broadcast"]) + replaceWith = ReplaceWith( + "GlobalScope.broadcast(context + parent, capacity, start, onCompletion, block)", + imports = ["kotlinx.coroutines.experimental.GlobalScope", "kotlinx.coroutines.experimental.channels.broadcast"] + ) ) public fun broadcast( - context: CoroutineContext = DefaultDispatcher, + context: CoroutineContext = Dispatchers.Default, capacity: Int = 1, start: CoroutineStart = CoroutineStart.LAZY, parent: Job? = null, onCompletion: CompletionHandler? = null, block: suspend ProducerScope.() -> Unit ): BroadcastChannel = - GlobalScope.broadcast(context + (parent ?: DefaultDispatcher), capacity, start, onCompletion, block) + GlobalScope.broadcast(context + (parent ?: Dispatchers.Default), capacity, start, onCompletion, block) /** * Launches new coroutine to produce a stream of values by sending them to a broadcast channel @@ -56,7 +58,7 @@ public fun broadcast( * when the coroutine completes. * * Coroutine context is inherited from a [CoroutineScope], additional context elements can be specified with [context] argument. - * If the context does not have any dispatcher nor any other [ContinuationInterceptor], then [DefaultDispatcher] is used. + * If the context does not have any dispatcher nor any other [ContinuationInterceptor], then [Dispatchers.Default] is used. * The parent job is inherited from a [CoroutineScope] as well, but it can also be overridden * with corresponding [coroutineContext] element. * @@ -75,7 +77,7 @@ public fun broadcast( * * See [newCoroutineContext] for a description of debugging facilities that are available for newly created coroutine. * - * @param context context of the coroutine. The default value is [DefaultDispatcher]. + * @param context additional to [CoroutineScope.coroutineContext] context of the coroutine. * @param capacity capacity of the channel's buffer (1 by default). * @param start coroutine start option. The default value is [CoroutineStart.LAZY]. * @param onCompletion optional completion handler for the producer coroutine (see [Job.invokeOnCompletion]). diff --git a/common/kotlinx-coroutines-core-common/src/channels/Channels.common.kt b/common/kotlinx-coroutines-core-common/src/channels/Channels.common.kt index be51b29084..8ad0db7a6c 100644 --- a/common/kotlinx-coroutines-core-common/src/channels/Channels.common.kt +++ b/common/kotlinx-coroutines-core-common/src/channels/Channels.common.kt @@ -18,7 +18,7 @@ internal const val DEFAULT_CLOSE_MESSAGE = "Channel was closed" /** * Returns a channel to read all element of the [Iterable]. */ -public fun Iterable.asReceiveChannel(context: CoroutineContext = Unconfined): ReceiveChannel = +public fun Iterable.asReceiveChannel(context: CoroutineContext = Dispatchers.Unconfined): ReceiveChannel = GlobalScope.produce(context) { for (element in this@asReceiveChannel) send(element) @@ -27,7 +27,7 @@ public fun Iterable.asReceiveChannel(context: CoroutineContext = Unconfin /** * Returns a channel to read all element of the [Sequence]. */ -public fun Sequence.asReceiveChannel(context: CoroutineContext = Unconfined): ReceiveChannel = +public fun Sequence.asReceiveChannel(context: CoroutineContext = Dispatchers.Unconfined): ReceiveChannel = GlobalScope.produce(context) { for (element in this@asReceiveChannel) send(element) @@ -498,7 +498,7 @@ public suspend inline fun ReceiveChannel.singleOrNull(predicate: (E) -> B * The operation is _intermediate_ and _stateless_. * This function [consumes][ReceiveChannel.consume] all elements of the original [ReceiveChannel]. */ -public fun ReceiveChannel.drop(n: Int, context: CoroutineContext = Unconfined): ReceiveChannel = +public fun ReceiveChannel.drop(n: Int, context: CoroutineContext = Dispatchers.Unconfined): ReceiveChannel = GlobalScope.produce(context, onCompletion = consumes()) { require(n >= 0) { "Requested element count $n is less than zero." } var remaining: Int = n @@ -520,7 +520,7 @@ public fun ReceiveChannel.drop(n: Int, context: CoroutineContext = Unconf * This function [consumes][ReceiveChannel.consume] all elements of the original [ReceiveChannel]. */ // todo: mark predicate with crossinline modifier when it is supported: https://youtrack.jetbrains.com/issue/KT-19159 -public fun ReceiveChannel.dropWhile(context: CoroutineContext = Unconfined, predicate: suspend (E) -> Boolean): ReceiveChannel = +public fun ReceiveChannel.dropWhile(context: CoroutineContext = Dispatchers.Unconfined, predicate: suspend (E) -> Boolean): ReceiveChannel = GlobalScope.produce(context, onCompletion = consumes()) { for (e in this@dropWhile) { if (!predicate(e)) { @@ -540,7 +540,7 @@ public fun ReceiveChannel.dropWhile(context: CoroutineContext = Unconfine * This function [consumes][ReceiveChannel.consume] all elements of the original [ReceiveChannel]. */ // todo: mark predicate with crossinline modifier when it is supported: https://youtrack.jetbrains.com/issue/KT-19159 -public fun ReceiveChannel.filter(context: CoroutineContext = Unconfined, predicate: suspend (E) -> Boolean): ReceiveChannel = +public fun ReceiveChannel.filter(context: CoroutineContext = Dispatchers.Unconfined, predicate: suspend (E) -> Boolean): ReceiveChannel = GlobalScope.produce(context, onCompletion = consumes()) { for (e in this@filter) { if (predicate(e)) send(e) @@ -556,7 +556,7 @@ public fun ReceiveChannel.filter(context: CoroutineContext = Unconfined, * This function [consumes][ReceiveChannel.consume] all elements of the original [ReceiveChannel]. */ // todo: mark predicate with crossinline modifier when it is supported: https://youtrack.jetbrains.com/issue/KT-19159 -public fun ReceiveChannel.filterIndexed(context: CoroutineContext = Unconfined, predicate: suspend (index: Int, E) -> Boolean): ReceiveChannel = +public fun ReceiveChannel.filterIndexed(context: CoroutineContext = Dispatchers.Unconfined, predicate: suspend (index: Int, E) -> Boolean): ReceiveChannel = GlobalScope.produce(context, onCompletion = consumes()) { var index = 0 for (e in this@filterIndexed) { @@ -601,7 +601,7 @@ public suspend inline fun > ReceiveChannel.filterIndexe * This function [consumes][ReceiveChannel.consume] all elements of the original [ReceiveChannel]. */ // todo: mark predicate with crossinline modifier when it is supported: https://youtrack.jetbrains.com/issue/KT-19159 -public fun ReceiveChannel.filterNot(context: CoroutineContext = Unconfined, predicate: suspend (E) -> Boolean): ReceiveChannel = +public fun ReceiveChannel.filterNot(context: CoroutineContext = Dispatchers.Unconfined, predicate: suspend (E) -> Boolean): ReceiveChannel = filter(context) { !predicate(it) } /** @@ -704,7 +704,7 @@ public suspend inline fun > ReceiveChannel.filterTo(des * The operation is _intermediate_ and _stateless_. * This function [consumes][ReceiveChannel.consume] all elements of the original [ReceiveChannel]. */ -public fun ReceiveChannel.take(n: Int, context: CoroutineContext = Unconfined): ReceiveChannel = +public fun ReceiveChannel.take(n: Int, context: CoroutineContext = Dispatchers.Unconfined): ReceiveChannel = GlobalScope.produce(context, onCompletion = consumes()) { if (n == 0) return@produce require(n >= 0) { "Requested element count $n is less than zero." } @@ -724,7 +724,7 @@ public fun ReceiveChannel.take(n: Int, context: CoroutineContext = Unconf * This function [consumes][ReceiveChannel.consume] all elements of the original [ReceiveChannel]. */ // todo: mark predicate with crossinline modifier when it is supported: https://youtrack.jetbrains.com/issue/KT-19159 -public fun ReceiveChannel.takeWhile(context: CoroutineContext = Unconfined, predicate: suspend (E) -> Boolean): ReceiveChannel = +public fun ReceiveChannel.takeWhile(context: CoroutineContext = Dispatchers.Unconfined, predicate: suspend (E) -> Boolean): ReceiveChannel = GlobalScope.produce(context, onCompletion = consumes()) { for (e in this@takeWhile) { if (!predicate(e)) return@produce @@ -908,7 +908,7 @@ public suspend fun ReceiveChannel.toSet(): Set = * This function [consumes][ReceiveChannel.consume] all elements of the original [ReceiveChannel]. */ // todo: mark predicate with crossinline modifier when it is supported: https://youtrack.jetbrains.com/issue/KT-19159 -public fun ReceiveChannel.flatMap(context: CoroutineContext = Unconfined, transform: suspend (E) -> ReceiveChannel): ReceiveChannel = +public fun ReceiveChannel.flatMap(context: CoroutineContext = Dispatchers.Unconfined, transform: suspend (E) -> ReceiveChannel): ReceiveChannel = GlobalScope.produce(context, onCompletion = consumes()) { for (e in this@flatMap) { transform(e).toChannel(this) @@ -985,7 +985,7 @@ public suspend inline fun >> Receiv * This function [consumes][ReceiveChannel.consume] all elements of the original [ReceiveChannel]. */ // todo: mark transform with crossinline modifier when it is supported: https://youtrack.jetbrains.com/issue/KT-19159 -public fun ReceiveChannel.map(context: CoroutineContext = Unconfined, transform: suspend (E) -> R): ReceiveChannel = +public fun ReceiveChannel.map(context: CoroutineContext = Dispatchers.Unconfined, transform: suspend (E) -> R): ReceiveChannel = GlobalScope.produce(context, onCompletion = consumes()) { consumeEach { send(transform(it)) @@ -1002,7 +1002,7 @@ public fun ReceiveChannel.map(context: CoroutineContext = Unconfined, * This function [consumes][ReceiveChannel.consume] all elements of the original [ReceiveChannel]. */ // todo: mark predicate with crossinline modifier when it is supported: https://youtrack.jetbrains.com/issue/KT-19159 -public fun ReceiveChannel.mapIndexed(context: CoroutineContext = Unconfined, transform: suspend (index: Int, E) -> R): ReceiveChannel = +public fun ReceiveChannel.mapIndexed(context: CoroutineContext = Dispatchers.Unconfined, transform: suspend (index: Int, E) -> R): ReceiveChannel = GlobalScope.produce(context, onCompletion = consumes()) { var index = 0 for (e in this@mapIndexed) { @@ -1020,7 +1020,7 @@ public fun ReceiveChannel.mapIndexed(context: CoroutineContext = Uncon * This function [consumes][ReceiveChannel.consume] all elements of the original [ReceiveChannel]. */ // todo: mark predicate with crossinline modifier when it is supported: https://youtrack.jetbrains.com/issue/KT-19159 -public fun ReceiveChannel.mapIndexedNotNull(context: CoroutineContext = Unconfined, transform: suspend (index: Int, E) -> R?): ReceiveChannel = +public fun ReceiveChannel.mapIndexedNotNull(context: CoroutineContext = Dispatchers.Unconfined, transform: suspend (index: Int, E) -> R?): ReceiveChannel = mapIndexed(context, transform).filterNotNull() /** @@ -1097,7 +1097,7 @@ public suspend inline fun > ReceiveChannel.mapIndexe * This function [consumes][ReceiveChannel.consume] all elements of the original [ReceiveChannel]. */ // todo: mark predicate with crossinline modifier when it is supported: https://youtrack.jetbrains.com/issue/KT-19159 -public fun ReceiveChannel.mapNotNull(context: CoroutineContext = Unconfined, transform: suspend (E) -> R?): ReceiveChannel = +public fun ReceiveChannel.mapNotNull(context: CoroutineContext = Dispatchers.Unconfined, transform: suspend (E) -> R?): ReceiveChannel = map(context, transform).filterNotNull() /** @@ -1162,7 +1162,7 @@ public suspend inline fun > ReceiveChannel.mapTo(des * The operation is _intermediate_ and _stateless_. * This function [consumes][ReceiveChannel.consume] all elements of the original [ReceiveChannel]. */ -public fun ReceiveChannel.withIndex(context: CoroutineContext = Unconfined): ReceiveChannel> = +public fun ReceiveChannel.withIndex(context: CoroutineContext = Dispatchers.Unconfined): ReceiveChannel> = GlobalScope.produce(context, onCompletion = consumes()) { var index = 0 for (e in this@withIndex) { @@ -1191,7 +1191,7 @@ public fun ReceiveChannel.distinct(): ReceiveChannel = * This function [consumes][ReceiveChannel.consume] all elements of the original [ReceiveChannel]. */ // todo: mark predicate with crossinline modifier when it is supported: https://youtrack.jetbrains.com/issue/KT-19159 -public fun ReceiveChannel.distinctBy(context: CoroutineContext = Unconfined, selector: suspend (E) -> K): ReceiveChannel = +public fun ReceiveChannel.distinctBy(context: CoroutineContext = Dispatchers.Unconfined, selector: suspend (E) -> K): ReceiveChannel = GlobalScope.produce(context, onCompletion = consumes()) { val keys = HashSet() for (e in this@distinctBy) { @@ -1529,7 +1529,7 @@ public infix fun ReceiveChannel.zip(other: ReceiveChannel): Receive * This function [consumes][consume] all elements of both the original [ReceiveChannel] and the `other` one. */ // todo: mark transform with crossinline modifier when it is supported: https://youtrack.jetbrains.com/issue/KT-19159 -public fun ReceiveChannel.zip(other: ReceiveChannel, context: CoroutineContext = Unconfined, transform: (a: E, b: R) -> V): ReceiveChannel = +public fun ReceiveChannel.zip(other: ReceiveChannel, context: CoroutineContext = Dispatchers.Unconfined, transform: (a: E, b: R) -> V): ReceiveChannel = GlobalScope.produce(context, onCompletion = consumesAll(this, other)) { val otherIterator = other.iterator() this@zip.consumeEach { element1 -> diff --git a/common/kotlinx-coroutines-core-common/src/channels/Produce.kt b/common/kotlinx-coroutines-core-common/src/channels/Produce.kt index b5d44e8766..9f234aa415 100644 --- a/common/kotlinx-coroutines-core-common/src/channels/Produce.kt +++ b/common/kotlinx-coroutines-core-common/src/channels/Produce.kt @@ -6,7 +6,6 @@ package kotlinx.coroutines.experimental.channels import kotlinx.coroutines.experimental.* import kotlinx.coroutines.experimental.channels.Channel.Factory.UNLIMITED -import kotlinx.coroutines.experimental.internal.* import kotlin.coroutines.experimental.* /** @@ -45,7 +44,7 @@ interface ProducerJob : ReceiveChannel, Job { * The running coroutine is cancelled when its receive channel is [cancelled][ReceiveChannel.cancel]. * * Coroutine context is inherited from a [CoroutineScope], additional context elements can be specified with [context] argument. - * If the context does not have any dispatcher nor any other [ContinuationInterceptor], then [DefaultDispatcher] is used. + * If the context does not have any dispatcher nor any other [ContinuationInterceptor], then [Dispatchers.Default] is used. * The parent job is inherited from a [CoroutineScope] as well, but it can also be overridden * with corresponding [coroutineContext] element. * @@ -61,7 +60,7 @@ interface ProducerJob : ReceiveChannel, Job { * * See [newCoroutineContext] for a description of debugging facilities that are available for newly created coroutine. * - * @param context context of the coroutine. The default value is [DefaultDispatcher]. + * @param context additional to [CoroutineScope.coroutineContext] context of the coroutine. * @param capacity capacity of the channel's buffer (no buffer by default). * @param onCompletion optional completion handler for the producer coroutine (see [Job.invokeOnCompletion]). * @param block the coroutine code. @@ -91,7 +90,7 @@ public fun CoroutineScope.produce( imports = ["kotlinx.coroutines.experimental.GlobalScope", "kotlinx.coroutines.experimental.channels.produce"]) ) public fun produce( - context: CoroutineContext = DefaultDispatcher, + context: CoroutineContext = Dispatchers.Default, capacity: Int = 0, onCompletion: CompletionHandler? = null, block: suspend ProducerScope.() -> Unit @@ -109,7 +108,7 @@ public fun produce( imports = ["kotlinx.coroutines.experimental.GlobalScope", "kotlinx.coroutines.experimental.channels.produce"]) ) public fun produce( - context: CoroutineContext = DefaultDispatcher, + context: CoroutineContext = Dispatchers.Default, capacity: Int = 0, parent: Job? = null, onCompletion: CompletionHandler? = null, @@ -120,7 +119,7 @@ public fun produce( /** @suppress **Deprecated**: Binary compatibility */ @Deprecated(message = "Binary compatibility", level = DeprecationLevel.HIDDEN) public fun produce( - context: CoroutineContext = DefaultDispatcher, + context: CoroutineContext = Dispatchers.Default, capacity: Int = 0, parent: Job? = null, block: suspend ProducerScope.() -> Unit @@ -129,7 +128,7 @@ public fun produce( /** @suppress **Deprecated**: Binary compatibility */ @Deprecated(message = "Binary compatibility", level = DeprecationLevel.HIDDEN) public fun produce( - context: CoroutineContext = DefaultDispatcher, + context: CoroutineContext = Dispatchers.Default, capacity: Int = 0, block: suspend ProducerScope.() -> Unit ): ProducerJob = diff --git a/common/kotlinx-coroutines-core-common/test/channels/ArrayBroadcastChannelTest.kt b/common/kotlinx-coroutines-core-common/test/channels/ArrayBroadcastChannelTest.kt index d381e81960..2b5c30e3c2 100644 --- a/common/kotlinx-coroutines-core-common/test/channels/ArrayBroadcastChannelTest.kt +++ b/common/kotlinx-coroutines-core-common/test/channels/ArrayBroadcastChannelTest.kt @@ -16,13 +16,13 @@ class ArrayBroadcastChannelTest : TestBase() { val s1 = channel.openSubscription() val s2 = channel.openSubscription() - val job1 = launch(Unconfined, CoroutineStart.UNDISPATCHED) { + val job1 = launch(Dispatchers.Unconfined, CoroutineStart.UNDISPATCHED) { expect(1) s1.receive() s1.cancel() } - val job2 = launch(Unconfined, CoroutineStart.UNDISPATCHED) { + val job2 = launch(Dispatchers.Unconfined, CoroutineStart.UNDISPATCHED) { expect(2) s2.receive() } diff --git a/common/kotlinx-coroutines-core-common/test/channels/ConflatedBroadcastChannelTest.kt b/common/kotlinx-coroutines-core-common/test/channels/ConflatedBroadcastChannelTest.kt index b946969cdd..f93f830ae3 100644 --- a/common/kotlinx-coroutines-core-common/test/channels/ConflatedBroadcastChannelTest.kt +++ b/common/kotlinx-coroutines-core-common/test/channels/ConflatedBroadcastChannelTest.kt @@ -16,13 +16,13 @@ class ConflatedBroadcastChannelTest : TestBase() { val s1 = channel.openSubscription() val s2 = channel.openSubscription() - val job1 = launch(Unconfined, CoroutineStart.UNDISPATCHED) { + val job1 = launch(Dispatchers.Unconfined, CoroutineStart.UNDISPATCHED) { expect(1) s1.receive() s1.cancel() } - val job2 = launch(Unconfined, CoroutineStart.UNDISPATCHED) { + val job2 = launch(Dispatchers.Unconfined, CoroutineStart.UNDISPATCHED) { expect(2) s2.receive() } diff --git a/common/kotlinx-coroutines-core-common/test/channels/ProduceTest.kt b/common/kotlinx-coroutines-core-common/test/channels/ProduceTest.kt index 40b4e5b0b2..0f958af7c1 100644 --- a/common/kotlinx-coroutines-core-common/test/channels/ProduceTest.kt +++ b/common/kotlinx-coroutines-core-common/test/channels/ProduceTest.kt @@ -84,7 +84,7 @@ class ProduceTest : TestBase() { @Test fun testCancelOnCompletionUnconfined() = runTest { - cancelOnCompletion(Unconfined) + cancelOnCompletion(Dispatchers.Unconfined) } @Test diff --git a/common/kotlinx-coroutines-core-common/test/sync/MutexTest.kt b/common/kotlinx-coroutines-core-common/test/sync/MutexTest.kt index 1fda2bc724..a62b1ea07c 100644 --- a/common/kotlinx-coroutines-core-common/test/sync/MutexTest.kt +++ b/common/kotlinx-coroutines-core-common/test/sync/MutexTest.kt @@ -64,7 +64,7 @@ class MutexTest : TestBase() { val mutex = Mutex(true) var done = 0 repeat(waiters) { - GlobalScope.launch(Unconfined) { // a lot of unconfined waiters + GlobalScope.launch(Dispatchers.Unconfined) { // a lot of unconfined waiters mutex.withLock { done++ } diff --git a/core/kotlinx-coroutines-core/README.md b/core/kotlinx-coroutines-core/README.md index e4bcce0c43..bd30844e9a 100644 --- a/core/kotlinx-coroutines-core/README.md +++ b/core/kotlinx-coroutines-core/README.md @@ -111,11 +111,9 @@ Components to ease writing unit-tests for code that contains coroutines with del [runBlocking]: https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines.experimental/run-blocking.html [CoroutineDispatcher]: https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines.experimental/-coroutine-dispatcher/index.html [DefaultDispatcher]: https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines.experimental/-default-dispatcher.html -[CommonPool]: https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines.experimental/-common-pool/index.html [newSingleThreadContext]: https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines.experimental/new-single-thread-context.html [newFixedThreadPoolContext]: https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines.experimental/new-fixed-thread-pool-context.html [java.util.concurrent.Executor.asCoroutineDispatcher]: https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines.experimental/java.util.concurrent.-executor/as-coroutine-dispatcher.html -[Unconfined]: https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines.experimental/-unconfined/index.html [NonCancellable]: https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines.experimental/-non-cancellable/index.html [CoroutineExceptionHandler]: https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines.experimental/-coroutine-exception-handler/index.html [delay]: https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines.experimental/delay.html diff --git a/core/kotlinx-coroutines-core/src/CommonPool.kt b/core/kotlinx-coroutines-core/src/CommonPool.kt index 086fbb38ec..27e3991c1d 100644 --- a/core/kotlinx-coroutines-core/src/CommonPool.kt +++ b/core/kotlinx-coroutines-core/src/CommonPool.kt @@ -20,7 +20,13 @@ import kotlin.coroutines.experimental.* * If there is a SecurityManager present (as would be if running inside a Java Web Start context) then a plain thread * pool is created. This is to work around the fact that ForkJoinPool creates threads that cannot perform * privileged actions. + * + * @suppress **Deprecated**: Use [Dispatchers.Default]. */ +@Deprecated( + message = "Use Dispatchers.Default", + replaceWith = ReplaceWith("Dispatchers.Default", + imports = ["kotlinx.coroutines.experimental.Dispatchers"])) object CommonPool : ExecutorCoroutineDispatcher() { /** diff --git a/core/kotlinx-coroutines-core/src/CoroutineContext.kt b/core/kotlinx-coroutines-core/src/CoroutineContext.kt index 853ccfd19b..402b504ebb 100644 --- a/core/kotlinx-coroutines-core/src/CoroutineContext.kt +++ b/core/kotlinx-coroutines-core/src/CoroutineContext.kt @@ -56,38 +56,34 @@ internal val useCoroutinesScheduler = systemProp(COROUTINES_SCHEDULER_PROPERTY_N } /** - * The default [CoroutineDispatcher] that is used by all standard builders like - * [launch][CoroutineScope.launch], [async][CoroutineScope.async], etc - * if no dispatcher nor any other [ContinuationInterceptor] is specified in their context. - * - * It is currently equal to [CommonPool], but the value is subject to change in the future. - * You can set system property "`kotlinx.coroutines.scheduler`" (either no value or to the value of "`on`") - * to use an experimental coroutine dispatcher that shares threads with [IO] dispatcher and thus can switch to - * [IO] context without performing an actual thread context switch. + * The default [CoroutineDispatcher] that is used by all standard builders. + * @suppress **Deprecated**: Use [Dispatchers.Default]. */ @Suppress("PropertyName") -public actual val DefaultDispatcher: CoroutineDispatcher = - if (useCoroutinesScheduler) BackgroundDispatcher else CommonPool +@Deprecated( + message = "Use Dispatchers.Default", + replaceWith = ReplaceWith("Dispatchers.Default", + imports = ["kotlinx.coroutines.experimental.Dispatchers"])) +public actual val DefaultDispatcher: CoroutineDispatcher + get() = Dispatchers.Default -/** - * Name of the property that defines the maximal number of threads that are used by [IO] coroutines dispatcher. - */ -public const val IO_PARALLELISM_PROPERTY_NAME = "kotlinx.coroutines.io.parallelism" +internal actual fun createDefaultDispatcher(): CoroutineDispatcher = + if (useCoroutinesScheduler) BackgroundDispatcher else CommonPool /** * The [CoroutineDispatcher] that is designed for offloading blocking IO tasks to a shared pool of threads. - * - * Additional threads in this pool are created and are shutdown on demand. - * The number of threads used by this dispatcher is limited by the value of - * "`kotlinx.coroutines.io.parallelism`" ([IO_PARALLELISM_PROPERTY_NAME]) system property. - * It defaults to the limit of 64 threads or the number of cores (whichever is larger). + * @suppress **Deprecated**: Use [Dispatchers.IO]. */ -public val IO: CoroutineDispatcher by lazy { - BackgroundDispatcher.blocking(systemProp(IO_PARALLELISM_PROPERTY_NAME, 64.coerceAtLeast(AVAILABLE_PROCESSORS))) -} +@Suppress("PropertyName") +@Deprecated( + message = "Use Dispatchers.IO", + replaceWith = ReplaceWith("Dispatchers.IO", + imports = ["kotlinx.coroutines.experimental.*"])) +public val IO: CoroutineDispatcher + get() = Dispatchers.IO /** - * Creates context for the new coroutine. It installs [DefaultDispatcher] when no other dispatcher nor + * Creates context for the new coroutine. It installs [Dispatchers.Default] when no other dispatcher nor * [ContinuationInterceptor] is specified, and adds optional support for debugging facilities (when turned on). * * **Debugging facilities:** In debug mode every coroutine is assigned a unique consecutive identifier. @@ -109,8 +105,8 @@ public val IO: CoroutineDispatcher by lazy { public actual fun CoroutineScope.newCoroutineContext(context: CoroutineContext): CoroutineContext { val combined = coroutineContext + context val debug = if (DEBUG) combined + CoroutineId(COROUTINE_ID.incrementAndGet()) else combined - return if (combined !== DefaultDispatcher && combined[ContinuationInterceptor] == null) - debug + DefaultDispatcher else debug + return if (combined !== Dispatchers.Default && combined[ContinuationInterceptor] == null) + debug + Dispatchers.Default else debug } /** diff --git a/core/kotlinx-coroutines-core/src/DefaultExecutor.kt b/core/kotlinx-coroutines-core/src/DefaultExecutor.kt index ab2b0bd76d..322914bd01 100644 --- a/core/kotlinx-coroutines-core/src/DefaultExecutor.kt +++ b/core/kotlinx-coroutines-core/src/DefaultExecutor.kt @@ -44,7 +44,8 @@ internal object DefaultExecutor : EventLoopBase(), Runnable { * runBlocking(eventLoop) { withTimeout { while(isActive) { ... } } } * ``` * - * Livelock is possible only if runBlocking is called on [DefaultDispatcher], but it's not exposed as public API + * Livelock is possible only if `runBlocking` is called on internal default executed (which is used by default [delay]), + * but it's not exposed as public API. */ override fun invokeOnTimeout(time: Long, unit: TimeUnit, block: Runnable): DisposableHandle = DelayedRunnableTask(time, unit, block).also { schedule(it) } diff --git a/core/kotlinx-coroutines-core/src/Dispatchers.kt b/core/kotlinx-coroutines-core/src/Dispatchers.kt new file mode 100644 index 0000000000..2426af28f7 --- /dev/null +++ b/core/kotlinx-coroutines-core/src/Dispatchers.kt @@ -0,0 +1,23 @@ +/* + * Copyright 2016-2018 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license. + */ + +package kotlinx.coroutines.experimental + +import kotlinx.coroutines.experimental.scheduling.* + +/** + * Name of the property that defines the maximal number of threads that are used by [Dispatchers.IO] coroutines dispatcher. + */ +public const val IO_PARALLELISM_PROPERTY_NAME = "kotlinx.coroutines.io.parallelism" + +/** + * The [CoroutineDispatcher] that is designed for offloading blocking IO tasks to a shared pool of threads. + * + * Additional threads in this pool are created and are shutdown on demand. + * The number of threads used by this dispatcher is limited by the value of + * "`kotlinx.coroutines.io.parallelism`" ([IO_PARALLELISM_PROPERTY_NAME]) system property. + * It defaults to the limit of 64 threads or the number of cores (whichever is larger). + */ +public val Dispatchers.IO: CoroutineDispatcher + get() = BackgroundDispatcher.IO diff --git a/core/kotlinx-coroutines-core/src/channels/Actor.kt b/core/kotlinx-coroutines-core/src/channels/Actor.kt index 115ae03179..dd933e3e24 100644 --- a/core/kotlinx-coroutines-core/src/channels/Actor.kt +++ b/core/kotlinx-coroutines-core/src/channels/Actor.kt @@ -6,7 +6,6 @@ package kotlinx.coroutines.experimental.channels import kotlinx.coroutines.experimental.* import kotlinx.coroutines.experimental.channels.Channel.Factory.UNLIMITED -import kotlinx.coroutines.experimental.internal.* import kotlinx.coroutines.experimental.intrinsics.* import kotlinx.coroutines.experimental.selects.* import kotlin.coroutines.experimental.* @@ -45,7 +44,7 @@ interface ActorJob : SendChannel { * when the coroutine completes. * * Coroutine context is inherited from a [CoroutineScope], additional context elements can be specified with [context] argument. - * If the context does not have any dispatcher nor any other [ContinuationInterceptor], then [DefaultDispatcher] is used. + * If the context does not have any dispatcher nor any other [ContinuationInterceptor], then [Dispatchers.Default] is used. * The parent job is inherited from a [CoroutineScope] as well, but it can also be overridden * with corresponding [coroutineContext] element. * @@ -106,7 +105,7 @@ interface ActorJob : SendChannel { * "`for (msg in channel)`" and other cancellable suspending functions throw [CancellationException] and actor * completes without processing remaining messages. * - * @param context additional to [CoroutineScope.coroutineContext] context of the coroutine + * @param context additional to [CoroutineScope.coroutineContext] context of the coroutine. * @param capacity capacity of the channel's buffer (no buffer by default). * @param start coroutine start option. The default value is [CoroutineStart.DEFAULT]. * @param onCompletion optional completion handler for the actor coroutine (see [Job.invokeOnCompletion]). @@ -140,7 +139,7 @@ public fun CoroutineScope.actor( imports = ["kotlinx.coroutines.experimental.GlobalScope", "kotlinx.coroutines.experimental.channels.actor"]) ) public fun actor( - context: CoroutineContext = DefaultDispatcher, + context: CoroutineContext = Dispatchers.Default, capacity: Int = 0, start: CoroutineStart = CoroutineStart.DEFAULT, onCompletion: CompletionHandler? = null, @@ -159,7 +158,7 @@ public fun actor( imports = ["kotlinx.coroutines.experimental.GlobalScope", "kotlinx.coroutines.experimental.channels.actor"]) ) public fun actor( - context: CoroutineContext = DefaultDispatcher, + context: CoroutineContext = Dispatchers.Default, capacity: Int = 0, start: CoroutineStart = CoroutineStart.DEFAULT, parent: Job? = null, @@ -171,7 +170,7 @@ public fun actor( /** @suppress **Deprecated**: Binary compatibility */ @Deprecated(message = "Binary compatibility", level = DeprecationLevel.HIDDEN) public fun actor( - context: CoroutineContext = DefaultDispatcher, + context: CoroutineContext = Dispatchers.Default, capacity: Int = 0, start: CoroutineStart = CoroutineStart.DEFAULT, parent: Job? = null, @@ -182,7 +181,7 @@ public fun actor( /** @suppress **Deprecated**: Binary compatibility */ @Deprecated(message = "Binary compatibility", level = DeprecationLevel.HIDDEN) public fun actor( - context: CoroutineContext = DefaultDispatcher, + context: CoroutineContext = Dispatchers.Default, capacity: Int = 0, start: CoroutineStart = CoroutineStart.DEFAULT, block: suspend ActorScope.() -> Unit diff --git a/core/kotlinx-coroutines-core/src/channels/TickerChannels.kt b/core/kotlinx-coroutines-core/src/channels/TickerChannels.kt index a402c4efaa..155aa6fd7a 100644 --- a/core/kotlinx-coroutines-core/src/channels/TickerChannels.kt +++ b/core/kotlinx-coroutines-core/src/channels/TickerChannels.kt @@ -47,7 +47,7 @@ enum class TickerMode { * * This channel stops producing elements immediately after [ReceiveChannel.cancel] invocation. * - * **Note** producer to this channel is dispatched via [Unconfined] dispatcher by default and started eagerly. + * **Note** producer to this channel is dispatched via [Dispatchers.Unconfined] by default and started eagerly. * * @param delay delay between each element. * @param unit unit of time that applies to [initialDelay] and [delay] (in milliseconds by default). @@ -64,7 +64,7 @@ public fun ticker( ): ReceiveChannel { require(delay >= 0) { "Expected non-negative delay, but has $delay" } require(initialDelay >= 0) { "Expected non-negative initial delay, but has $initialDelay" } - return GlobalScope.produce(Unconfined + context, capacity = 0) { + return GlobalScope.produce(Dispatchers.Unconfined + context, capacity = 0) { when (mode) { TickerMode.FIXED_PERIOD -> fixedPeriodTicker(delay, unit, initialDelay, channel) TickerMode.FIXED_DELAY -> fixedDelayTicker(delay, unit, initialDelay, channel) diff --git a/core/kotlinx-coroutines-core/src/scheduling/ExperimentalCoroutineDispatcher.kt b/core/kotlinx-coroutines-core/src/scheduling/ExperimentalCoroutineDispatcher.kt index 4845136719..7abbf90350 100644 --- a/core/kotlinx-coroutines-core/src/scheduling/ExperimentalCoroutineDispatcher.kt +++ b/core/kotlinx-coroutines-core/src/scheduling/ExperimentalCoroutineDispatcher.kt @@ -6,13 +6,16 @@ package kotlinx.coroutines.experimental.scheduling import kotlinx.atomicfu.* import kotlinx.coroutines.experimental.* +import kotlinx.coroutines.experimental.internal.* import java.util.concurrent.* import kotlin.coroutines.experimental.* /** * Default instance of coroutine dispatcher for background coroutines (as opposed to UI coroutines). */ -internal object BackgroundDispatcher : ExperimentalCoroutineDispatcher() +internal object BackgroundDispatcher : ExperimentalCoroutineDispatcher() { + val IO = blocking(systemProp(IO_PARALLELISM_PROPERTY_NAME, 64.coerceAtLeast(AVAILABLE_PROCESSORS))) +} /** * @suppress **This is unstable API and it is subject to change.** diff --git a/core/kotlinx-coroutines-core/test/DebugThreadNameTest.kt b/core/kotlinx-coroutines-core/test/DebugThreadNameTest.kt index ff91555c88..a42f94580a 100644 --- a/core/kotlinx-coroutines-core/test/DebugThreadNameTest.kt +++ b/core/kotlinx-coroutines-core/test/DebugThreadNameTest.kt @@ -49,7 +49,7 @@ class DebugThreadNameTest : TestBase() { @Test fun testWithContext() = runTest { assertName("coroutine#1") - withContext(DefaultDispatcher) { + withContext(Dispatchers.Default) { assertName("coroutine#1") yield() assertName("coroutine#1") diff --git a/core/kotlinx-coroutines-core/test/IODispatcherTest.kt b/core/kotlinx-coroutines-core/test/IODispatcherTest.kt index 094ec62244..e0487c2cdb 100644 --- a/core/kotlinx-coroutines-core/test/IODispatcherTest.kt +++ b/core/kotlinx-coroutines-core/test/IODispatcherTest.kt @@ -13,7 +13,7 @@ class IODispatcherTest : TestBase() { // just a very basic test that is dispatcher works and indeed uses background thread val mainThread = Thread.currentThread() expect(1) - withContext(IO) { + withContext(Dispatchers.IO) { expect(2) assertNotSame(mainThread, Thread.currentThread()) } diff --git a/core/kotlinx-coroutines-core/test/ThreadContextElementTest.kt b/core/kotlinx-coroutines-core/test/ThreadContextElementTest.kt index 47a2cf2669..c19ba2bcc5 100644 --- a/core/kotlinx-coroutines-core/test/ThreadContextElementTest.kt +++ b/core/kotlinx-coroutines-core/test/ThreadContextElementTest.kt @@ -42,7 +42,7 @@ class ThreadContextElementTest : TestBase() { val data = MyData() val element = MyElement(data) val job = GlobalScope.launch( - context = DefaultDispatcher + exceptionHandler + element, + context = Dispatchers.Default + exceptionHandler + element, start = CoroutineStart.UNDISPATCHED ) { assertSame(data, myThreadLocal.get()) diff --git a/core/kotlinx-coroutines-core/test/WithDefaultContextTest.kt b/core/kotlinx-coroutines-core/test/WithDefaultContextTest.kt index 901a957c19..3cd09062f9 100644 --- a/core/kotlinx-coroutines-core/test/WithDefaultContextTest.kt +++ b/core/kotlinx-coroutines-core/test/WithDefaultContextTest.kt @@ -10,7 +10,7 @@ class WithDefaultContextTest : TestBase() { @Test fun testNoSuspend() = runTest { expect(1) - val result = withContext(DefaultDispatcher) { + val result = withContext(Dispatchers.Default) { expect(2) "OK" } @@ -21,7 +21,7 @@ class WithDefaultContextTest : TestBase() { @Test fun testWithSuspend() = runTest { expect(1) - val result = withContext(DefaultDispatcher) { + val result = withContext(Dispatchers.Default) { expect(2) delay(100) expect(3) diff --git a/core/kotlinx-coroutines-core/test/channels/BroadcastChannelSubStressTest.kt b/core/kotlinx-coroutines-core/test/channels/BroadcastChannelSubStressTest.kt index dc94d4b5c8..ca264c7621 100644 --- a/core/kotlinx-coroutines-core/test/channels/BroadcastChannelSubStressTest.kt +++ b/core/kotlinx-coroutines-core/test/channels/BroadcastChannelSubStressTest.kt @@ -37,7 +37,7 @@ class BroadcastChannelSubStressTest( @Test fun testStress() = runBlocking { println("--- BroadcastChannelSubStressTest $kind") - val ctx = coroutineContext + DefaultDispatcher + val ctx = coroutineContext + Dispatchers.Default val sender = launch(context = ctx + CoroutineName("Sender")) { while (isActive) { diff --git a/core/kotlinx-coroutines-core/test/channels/ChannelSendReceiveStressTest.kt b/core/kotlinx-coroutines-core/test/channels/ChannelSendReceiveStressTest.kt index f307ae9107..4330798d54 100644 --- a/core/kotlinx-coroutines-core/test/channels/ChannelSendReceiveStressTest.kt +++ b/core/kotlinx-coroutines-core/test/channels/ChannelSendReceiveStressTest.kt @@ -49,7 +49,7 @@ class ChannelSendReceiveStressTest( println("--- ChannelSendReceiveStressTest $kind with nSenders=$nSenders, nReceivers=$nReceivers") val receivers = List(nReceivers) { receiverIndex -> // different event receivers use different code - launch(DefaultDispatcher + CoroutineName("receiver$receiverIndex")) { + launch(Dispatchers.Default + CoroutineName("receiver$receiverIndex")) { when (receiverIndex % 5) { 0 -> doReceive(receiverIndex) 1 -> doReceiveOrNull(receiverIndex) @@ -61,7 +61,7 @@ class ChannelSendReceiveStressTest( } } val senders = List(nSenders) { senderIndex -> - launch(DefaultDispatcher + CoroutineName("sender$senderIndex")) { + launch(Dispatchers.Default + CoroutineName("sender$senderIndex")) { when (senderIndex % 2) { 0 -> doSend(senderIndex) 1 -> doSendSelect(senderIndex) diff --git a/core/kotlinx-coroutines-core/test/channels/ConflatedBroadcastChannelNotifyStressTest.kt b/core/kotlinx-coroutines-core/test/channels/ConflatedBroadcastChannelNotifyStressTest.kt index c608b261ea..bebcd37909 100644 --- a/core/kotlinx-coroutines-core/test/channels/ConflatedBroadcastChannelNotifyStressTest.kt +++ b/core/kotlinx-coroutines-core/test/channels/ConflatedBroadcastChannelNotifyStressTest.kt @@ -28,7 +28,7 @@ class ConflatedBroadcastChannelNotifyStressTest : TestBase() { fun testStressNotify()= runBlocking { println("--- ConflatedBroadcastChannelNotifyStressTest") val senders = List(nSenders) { senderId -> - launch(DefaultDispatcher + CoroutineName("Sender$senderId")) { + launch(Dispatchers.Default + CoroutineName("Sender$senderId")) { repeat(nEvents) { i -> if (i % nSenders == senderId) { broadcast.offer(i) @@ -40,7 +40,7 @@ class ConflatedBroadcastChannelNotifyStressTest : TestBase() { } } val receivers = List(nReceivers) { receiverId -> - launch(DefaultDispatcher + CoroutineName("Receiver$receiverId")) { + launch(Dispatchers.Default + CoroutineName("Receiver$receiverId")) { var last = -1 while (isActive) { val i = waitForEvent() diff --git a/core/kotlinx-coroutines-core/test/channels/SimpleSendReceiveJvmTest.kt b/core/kotlinx-coroutines-core/test/channels/SimpleSendReceiveJvmTest.kt index 3eab32d4be..1198952f75 100644 --- a/core/kotlinx-coroutines-core/test/channels/SimpleSendReceiveJvmTest.kt +++ b/core/kotlinx-coroutines-core/test/channels/SimpleSendReceiveJvmTest.kt @@ -34,7 +34,7 @@ class SimpleSendReceiveJvmTest( @Test fun testSimpleSendReceive() = runBlocking { - val ctx = if (concurrent) DefaultDispatcher else coroutineContext + val ctx = if (concurrent) Dispatchers.Default else coroutineContext launch(ctx) { repeat(n) { channel.send(it) } channel.close() diff --git a/core/kotlinx-coroutines-core/test/guide/example-cancel-02.kt b/core/kotlinx-coroutines-core/test/guide/example-cancel-02.kt index f558abedb0..a175490dd1 100644 --- a/core/kotlinx-coroutines-core/test/guide/example-cancel-02.kt +++ b/core/kotlinx-coroutines-core/test/guide/example-cancel-02.kt @@ -9,7 +9,7 @@ import kotlinx.coroutines.experimental.* fun main(args: Array) = runBlocking { val startTime = timeSource.currentTimeMillis() - val job = launch(DefaultDispatcher) { + val job = launch(Dispatchers.Default) { var nextPrintTime = startTime var i = 0 while (i < 5) { // computation loop, just wastes CPU diff --git a/core/kotlinx-coroutines-core/test/guide/example-cancel-03.kt b/core/kotlinx-coroutines-core/test/guide/example-cancel-03.kt index fe05d708b5..e44e502d35 100644 --- a/core/kotlinx-coroutines-core/test/guide/example-cancel-03.kt +++ b/core/kotlinx-coroutines-core/test/guide/example-cancel-03.kt @@ -9,7 +9,7 @@ import kotlinx.coroutines.experimental.* fun main(args: Array) = runBlocking { val startTime = timeSource.currentTimeMillis() - val job = launch(DefaultDispatcher) { + val job = launch(Dispatchers.Default) { var nextPrintTime = startTime var i = 0 while (isActive) { // cancellable computation loop diff --git a/core/kotlinx-coroutines-core/test/guide/example-context-01.kt b/core/kotlinx-coroutines-core/test/guide/example-context-01.kt index 11b351b416..c417dda7bb 100644 --- a/core/kotlinx-coroutines-core/test/guide/example-context-01.kt +++ b/core/kotlinx-coroutines-core/test/guide/example-context-01.kt @@ -12,11 +12,11 @@ fun main(args: Array) = runBlocking { launch { // context of the parent, main runBlocking coroutine println("main runBlocking : I'm working in thread ${Thread.currentThread().name}") } - launch(Unconfined) { // not confined -- will work with main thread + launch(Dispatchers.Unconfined) { // not confined -- will work with main thread println("Unconfined : I'm working in thread ${Thread.currentThread().name}") } - launch(DefaultDispatcher) { // will get dispatched to ForkJoinPool.commonPool (or equivalent) - println("DefaultDispatcher : I'm working in thread ${Thread.currentThread().name}") + launch(Dispatchers.Default) { // will get dispatched to ForkJoinPool.commonPool (or equivalent) + println("Default : I'm working in thread ${Thread.currentThread().name}") } launch(newSingleThreadContext("MyOwnThread")) { // will get its own new thread println("newSingleThreadContext: I'm working in thread ${Thread.currentThread().name}") diff --git a/core/kotlinx-coroutines-core/test/guide/example-context-02.kt b/core/kotlinx-coroutines-core/test/guide/example-context-02.kt index f143c5ef74..4d3eb0da39 100644 --- a/core/kotlinx-coroutines-core/test/guide/example-context-02.kt +++ b/core/kotlinx-coroutines-core/test/guide/example-context-02.kt @@ -9,7 +9,7 @@ import kotlinx.coroutines.experimental.* import kotlin.coroutines.experimental.* fun main(args: Array) = runBlocking { - launch(Unconfined) { // not confined -- will work with main thread + launch(Dispatchers.Unconfined) { // not confined -- will work with main thread println("Unconfined : I'm working in thread ${Thread.currentThread().name}") delay(500) println("Unconfined : After delay in thread ${Thread.currentThread().name}") diff --git a/core/kotlinx-coroutines-core/test/guide/example-context-09.kt b/core/kotlinx-coroutines-core/test/guide/example-context-09.kt index 60ec0e2bd8..1788442c7a 100644 --- a/core/kotlinx-coroutines-core/test/guide/example-context-09.kt +++ b/core/kotlinx-coroutines-core/test/guide/example-context-09.kt @@ -9,7 +9,7 @@ import kotlinx.coroutines.experimental.* import kotlin.coroutines.experimental.* fun main(args: Array) = runBlocking { - launch(DefaultDispatcher + CoroutineName("test")) { + launch(Dispatchers.Default + CoroutineName("test")) { println("I'm working in thread ${Thread.currentThread().name}") } } diff --git a/core/kotlinx-coroutines-core/test/guide/example-context-10.kt b/core/kotlinx-coroutines-core/test/guide/example-context-10.kt index eec2f98c6d..c1294902fb 100644 --- a/core/kotlinx-coroutines-core/test/guide/example-context-10.kt +++ b/core/kotlinx-coroutines-core/test/guide/example-context-10.kt @@ -22,7 +22,7 @@ class Activity : CoroutineScope { // class Activity continues override val coroutineContext: CoroutineContext - get() = DefaultDispatcher + job + get() = Dispatchers.Default + job // to be continued ... // class Activity continues diff --git a/core/kotlinx-coroutines-core/test/guide/example-context-11.kt b/core/kotlinx-coroutines-core/test/guide/example-context-11.kt index 1926a5e6af..d1ac5fa719 100644 --- a/core/kotlinx-coroutines-core/test/guide/example-context-11.kt +++ b/core/kotlinx-coroutines-core/test/guide/example-context-11.kt @@ -13,7 +13,7 @@ val threadLocal = ThreadLocal() // declare thread-local variable fun main(args: Array) = runBlocking { threadLocal.set("main") println("Pre-main, current thread: ${Thread.currentThread()}, thread local value: '${threadLocal.get()}'") - val job = launch(DefaultDispatcher + threadLocal.asContextElement(value = "launch")) { + val job = launch(Dispatchers.Default + threadLocal.asContextElement(value = "launch")) { println("Launch start, current thread: ${Thread.currentThread()}, thread local value: '${threadLocal.get()}'") yield() println("After yield, current thread: ${Thread.currentThread()}, thread local value: '${threadLocal.get()}'") diff --git a/core/kotlinx-coroutines-core/test/guide/example-sync-01b.kt b/core/kotlinx-coroutines-core/test/guide/example-sync-01b.kt index 9ec6476ddf..0e2d4f028c 100644 --- a/core/kotlinx-coroutines-core/test/guide/example-sync-01b.kt +++ b/core/kotlinx-coroutines-core/test/guide/example-sync-01b.kt @@ -27,7 +27,7 @@ val mtContext = newFixedThreadPoolContext(2, "mtPool") // explicitly define cont var counter = 0 fun main(args: Array) = runBlocking { - CoroutineScope(mtContext).massiveRun { // use it instead of DefaultDispatcher in this sample and below + CoroutineScope(mtContext).massiveRun { // use it instead of Dispatchers.Default in this sample and below counter++ } println("Counter = $counter") diff --git a/core/kotlinx-coroutines-core/test/guide/test/GuideTest.kt b/core/kotlinx-coroutines-core/test/guide/test/GuideTest.kt index 1255279a1a..4f89a73c66 100644 --- a/core/kotlinx-coroutines-core/test/guide/test/GuideTest.kt +++ b/core/kotlinx-coroutines-core/test/guide/test/GuideTest.kt @@ -220,7 +220,7 @@ class GuideTest { fun testKotlinxCoroutinesExperimentalGuideContext01() { test("KotlinxCoroutinesExperimentalGuideContext01") { kotlinx.coroutines.experimental.guide.context01.main(emptyArray()) }.verifyLinesStartUnordered( "Unconfined : I'm working in thread main", - "DefaultDispatcher : I'm working in thread CommonPool-worker-1", + "Default : I'm working in thread CommonPool-worker-1", "newSingleThreadContext: I'm working in thread MyOwnThread", "main runBlocking : I'm working in thread main" ) diff --git a/coroutines-guide.md b/coroutines-guide.md index b5a55d0ea9..d0da8e9f44 100644 --- a/coroutines-guide.md +++ b/coroutines-guide.md @@ -482,7 +482,7 @@ example shows: ```kotlin fun main(args: Array) = runBlocking { val startTime = System.currentTimeMillis() - val job = launch(DefaultDispatcher) { + val job = launch(Dispatchers.Default) { var nextPrintTime = startTime var i = 0 while (i < 5) { // computation loop, just wastes CPU @@ -526,7 +526,7 @@ Replace `while (i < 5)` in the previous example with `while (isActive)` and reru ```kotlin fun main(args: Array) = runBlocking { val startTime = System.currentTimeMillis() - val job = launch(DefaultDispatcher) { + val job = launch(Dispatchers.Default) { var nextPrintTime = startTime var i = 0 while (isActive) { // cancellable computation loop @@ -1019,11 +1019,11 @@ fun main(args: Array) = runBlocking { launch { // context of the parent, main runBlocking coroutine println("main runBlocking : I'm working in thread ${Thread.currentThread().name}") } - launch(Unconfined) { // not confined -- will work with main thread + launch(Dispatchers.Unconfined) { // not confined -- will work with main thread println("Unconfined : I'm working in thread ${Thread.currentThread().name}") } - launch(DefaultDispatcher) { // will get dispatched to ForkJoinPool.commonPool (or equivalent) - println("DefaultDispatcher : I'm working in thread ${Thread.currentThread().name}") + launch(Dispatchers.Default) { // will get dispatched to ForkJoinPool.commonPool (or equivalent) + println("Default : I'm working in thread ${Thread.currentThread().name}") } launch(newSingleThreadContext("MyOwnThread")) { // will get its own new thread println("newSingleThreadContext: I'm working in thread ${Thread.currentThread().name}") @@ -1037,7 +1037,7 @@ It produces the following output (maybe in different order): ```text Unconfined : I'm working in thread main -DefaultDispatcher : I'm working in thread CommonPool-worker-1 +Default : I'm working in thread CommonPool-worker-1 newSingleThreadContext: I'm working in thread MyOwnThread main runBlocking : I'm working in thread main ``` @@ -1048,12 +1048,12 @@ When `launch { ... }` is used without parameters, it inherits the context (and t from the [CoroutineScope] that it is being launched from. In this case, it inherits the context of the main `runBlocking` coroutine which runs in the `main` thread. -[Unconfined] is a special dispatcher that also appears to run in the `main` thread, but it is, +[Dispatchers.Unconfined] is a special dispatcher that also appears to run in the `main` thread, but it is, in fact, a different mechanism that is explained later. The default dispatcher, that is used when coroutines are launched in [GlobalScope], -is represented by [DefaultDispatcher] and uses shared background pool of threads, -so `launch(DefaultDispatcher) { ... }` uses the same dispatcher as `GlobalScope.launch { ... }`. +is represented by [Dispatchers.Default] and uses shared background pool of threads, +so `launch(Dispatchers.Default) { ... }` uses the same dispatcher as `GlobalScope.launch { ... }`. [newSingleThreadContext] creates a new thread for the coroutine to run. A dedicated thread is a very expensive resource. @@ -1062,7 +1062,7 @@ function, or stored in a top-level variable and reused throughout the applicatio ### Unconfined vs confined dispatcher -The [Unconfined] coroutine dispatcher starts coroutine in the caller thread, but only until the +The [Dispatchers.Unconfined] coroutine dispatcher starts coroutine in the caller thread, but only until the first suspension point. After suspension it resumes in the thread that is fully determined by the suspending function that was invoked. Unconfined dispatcher is appropriate when coroutine does not consume CPU time nor updates any shared data (like UI) that is confined to a specific thread. @@ -1078,7 +1078,7 @@ import kotlin.coroutines.experimental.* ```kotlin fun main(args: Array) = runBlocking { - launch(Unconfined) { // not confined -- will work with main thread + launch(Dispatchers.Unconfined) { // not confined -- will work with main thread println("Unconfined : I'm working in thread ${Thread.currentThread().name}") delay(500) println("Unconfined : After delay in thread ${Thread.currentThread().name}") @@ -1108,10 +1108,10 @@ So, the coroutine that had inherited context of `runBlocking {...}` continues to in the `main` thread, while the unconfined one had resumed in the default executor thread that [delay] function is using. -> [Unconfined] dispatcher is an advanced mechanism that can be helpful in certain corner cases where +> Unconfined dispatcher is an advanced mechanism that can be helpful in certain corner cases where dispatching of coroutine for its execution later is not needed or produces undesirable side-effects, because some operation in a coroutine must be performed right away. -[Unconfined] dispatcher should not be used in general code. +Unconfined dispatcher should not be used in general code. ### Debugging coroutines and threads @@ -1380,7 +1380,7 @@ import kotlin.coroutines.experimental.* ```kotlin fun main(args: Array) = runBlocking { - launch(DefaultDispatcher + CoroutineName("test")) { + launch(Dispatchers.Default + CoroutineName("test")) { println("I'm working in thread ${Thread.currentThread().name}") } } @@ -1428,12 +1428,12 @@ class Activity : CoroutineScope { We also implement [CoroutineScope] interface in this `Actvity` class. We only need to provide an override for its [CoroutineScope.coroutineContext] property to specify the context for coroutines launched in its -scope. We combine the desired dispatcher (we used [DefaultDispatcher] in this example) and a job: +scope. We combine the desired dispatcher (we used [Dispatchers.Default] in this example) and a job: ```kotlin // class Activity continues override val coroutineContext: CoroutineContext - get() = DefaultDispatcher + job + get() = Dispatchers.Default + job // to be continued ... ``` @@ -1509,7 +1509,7 @@ val threadLocal = ThreadLocal() // declare thread-local variable fun main(args: Array) = runBlocking { threadLocal.set("main") println("Pre-main, current thread: ${Thread.currentThread()}, thread local value: '${threadLocal.get()}'") - val job = launch(DefaultDispatcher + threadLocal.asContextElement(value = "launch")) { + val job = launch(Dispatchers.Default + threadLocal.asContextElement(value = "launch")) { println("Launch start, current thread: ${Thread.currentThread()}, thread local value: '${threadLocal.get()}'") yield() println("After yield, current thread: ${Thread.currentThread()}, thread local value: '${threadLocal.get()}'") @@ -1521,7 +1521,7 @@ fun main(args: Array) = runBlocking { > You can get full code [here](core/kotlinx-coroutines-core/test/guide/example-context-11.kt) -In this example we launch new coroutine in a background thread pool using [DefaultDispatcher], so +In this example we launch new coroutine in a background thread pool using [Dispatchers.Default], so it works on a different threads from a thread pool, but it still has the value of thread local variable, that we've specified using `threadLocal.asContextElement(value = "launch")`, no matter on what thread the coroutine is executed. @@ -2077,7 +2077,7 @@ coroutine builder from the standard library. Replace `produce` with `buildIterator`, `send` with `yield`, `receive` with `next`, `ReceiveChannel` with `Iterator`, and get rid of the coroutine scope. You will not need `runBlocking` either. However, the benefit of a pipeline that uses channels as shown above is that it can actually use -multiple CPU cores if you run it in [DefaultDispatcher] context. +multiple CPU cores if you run it in [Dispatchers.Default] context. Anyway, this is an extremely impractical way to find prime numbers. In practice, pipelines do involve some other suspending invocations (like asynchronous calls to remote services) and these pipelines cannot be @@ -2358,7 +2358,7 @@ delay between elements. ## Shared mutable state and concurrency -Coroutines can be executed concurrently using a multi-threaded dispatcher like the [DefaultDispatcher]. It presents +Coroutines can be executed concurrently using a multi-threaded dispatcher like the [Dispatchers.Default]. It presents all the usual concurrency problems. The main problem being synchronization of access to **shared mutable state**. Some solutions to this problem in the land of coroutines are similar to the solutions in the multi-threaded world, but others are unique. @@ -2404,7 +2404,7 @@ suspend fun CoroutineScope.massiveRun(action: suspend () -> Unit) { We start with a very simple action that increments a shared mutable variable using -multi-threaded [DefaultDispatcher] that is used in [GlobalScope]. +multi-threaded [Dispatchers.Default] that is used in [GlobalScope]. ```kotlin var counter = 0 @@ -2436,7 +2436,7 @@ val mtContext = newFixedThreadPoolContext(2, "mtPool") // explicitly define cont var counter = 0 fun main(args: Array) = runBlocking { - CoroutineScope(mtContext).massiveRun { // use it instead of DefaultDispatcher in this sample and below + CoroutineScope(mtContext).massiveRun { // use it instead of Dispatchers.Default in this sample and below counter++ } println("Counter = $counter") @@ -2535,7 +2535,7 @@ Counter = 100000 --> This code works very slowly, because it does _fine-grained_ thread-confinement. Each individual increment switches -from multi-threaded [DefaultDispatcher] context to the single-threaded context using [withContext] block. +from multi-threaded [Dispatchers.Default] context to the single-threaded context using [withContext] block. ### Thread confinement coarse-grained @@ -3066,8 +3066,8 @@ Channel was closed [Deferred.await]: https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines.experimental/-deferred/await.html [Job.start]: https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines.experimental/-job/start.html [CoroutineDispatcher]: https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines.experimental/-coroutine-dispatcher/index.html -[Unconfined]: https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines.experimental/-unconfined/index.html -[DefaultDispatcher]: https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines.experimental/-default-dispatcher.html +[Dispatchers.Unconfined]: https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines.experimental/-dispatchers/-unconfined.html +[Dispatchers.Default]: https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines.experimental/-dispatchers/-default.html [newSingleThreadContext]: https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines.experimental/new-single-thread-context.html [ThreadPoolDispatcher.close]: https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines.experimental/-thread-pool-dispatcher/close.html [newCoroutineContext]: https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines.experimental/new-coroutine-context.html diff --git a/integration/kotlinx-coroutines-guava/src/ListenableFuture.kt b/integration/kotlinx-coroutines-guava/src/ListenableFuture.kt index 29eb8ca564..bb77ad03fe 100644 --- a/integration/kotlinx-coroutines-guava/src/ListenableFuture.kt +++ b/integration/kotlinx-coroutines-guava/src/ListenableFuture.kt @@ -14,7 +14,7 @@ import kotlin.coroutines.experimental.* * The running coroutine is cancelled when the resulting future is cancelled or otherwise completed. * * Coroutine context is inherited from a [CoroutineScope], additional context elements can be specified with [context] argument. - * If the context does not have any dispatcher nor any other [ContinuationInterceptor], then [DefaultDispatcher] is used. + * If the context does not have any dispatcher nor any other [ContinuationInterceptor], then [Dispatchers.Default] is used. * The parent job is inherited from a [CoroutineScope] as well, but it can also be overridden * with corresponding [coroutineContext] element. * @@ -26,14 +26,13 @@ import kotlin.coroutines.experimental.* * * See [newCoroutineContext][CoroutineScope.newCoroutineContext] for a description of debugging facilities that are available for newly created coroutine. * - * @param context context of the coroutine. The default value is [DefaultDispatcher]. + * @param context additional to [CoroutineScope.coroutineContext] context of the coroutine. * @param start coroutine start option. The default value is [CoroutineStart.DEFAULT]. - * @param parent explicitly specifies the parent job, overrides job from the [context] (if any). * @param onCompletion optional completion handler for the coroutine (see [Job.invokeOnCompletion]). * @param block the coroutine code. */ public fun CoroutineScope.future( - context: CoroutineContext = DefaultDispatcher, + context: CoroutineContext = EmptyCoroutineContext, start: CoroutineStart = CoroutineStart.DEFAULT, onCompletion: CompletionHandler? = null, block: suspend CoroutineScope.() -> T @@ -58,7 +57,7 @@ public fun CoroutineScope.future( imports = ["kotlinx.coroutines.experimental.GlobalScope", "kotlinx.coroutines.experimental.future.future"]) ) public fun future( - context: CoroutineContext = DefaultDispatcher, + context: CoroutineContext = Dispatchers.Default, start: CoroutineStart = CoroutineStart.DEFAULT, onCompletion: CompletionHandler? = null, block: suspend CoroutineScope.() -> T @@ -75,7 +74,7 @@ public fun future( imports = ["kotlinx.coroutines.experimental.GlobalScope", "kotlinx.coroutines.experimental.future.future"]) ) public fun future( - context: CoroutineContext = DefaultDispatcher, + context: CoroutineContext = Dispatchers.Default, start: CoroutineStart = CoroutineStart.DEFAULT, parent: Job? = null, onCompletion: CompletionHandler? = null, @@ -86,7 +85,7 @@ public fun future( /** @suppress **Deprecated**: Binary compatibility */ @Deprecated(message = "Binary compatibility", level = DeprecationLevel.HIDDEN) public fun future( - context: CoroutineContext = DefaultDispatcher, + context: CoroutineContext = Dispatchers.Default, start: CoroutineStart = CoroutineStart.DEFAULT, parent: Job? = null, block: suspend CoroutineScope.() -> T @@ -96,7 +95,7 @@ public fun future( /** @suppress **Deprecated**: Binary compatibility */ @Deprecated(message = "Binary compatibility", level = DeprecationLevel.HIDDEN) public fun future( - context: CoroutineContext = DefaultDispatcher, + context: CoroutineContext = Dispatchers.Default, start: CoroutineStart = CoroutineStart.DEFAULT, block: suspend CoroutineScope.() -> T ): ListenableFuture = diff --git a/integration/kotlinx-coroutines-guava/test/ListenableFutureTest.kt b/integration/kotlinx-coroutines-guava/test/ListenableFutureTest.kt index 25f19f33b0..b0576384c6 100644 --- a/integration/kotlinx-coroutines-guava/test/ListenableFutureTest.kt +++ b/integration/kotlinx-coroutines-guava/test/ListenableFutureTest.kt @@ -34,7 +34,7 @@ class ListenableFutureTest : TestBase() { fun testAwaitWithContext() = runTest { val future = SettableFuture.create() val deferred = async { - withContext(DefaultDispatcher) { + withContext(Dispatchers.Default) { future.await() } } @@ -47,7 +47,7 @@ class ListenableFutureTest : TestBase() { fun testAwaitWithContextCancellation() = runTest(expected = {it is IOException}) { val future = SettableFuture.create() val deferred = async { - withContext(DefaultDispatcher) { + withContext(Dispatchers.Default) { future.await() } } diff --git a/integration/kotlinx-coroutines-jdk8/src/channels8/Channels.kt b/integration/kotlinx-coroutines-jdk8/src/channels8/Channels.kt index 3c51d42fa9..c199328d1b 100644 --- a/integration/kotlinx-coroutines-jdk8/src/channels8/Channels.kt +++ b/integration/kotlinx-coroutines-jdk8/src/channels8/Channels.kt @@ -12,12 +12,12 @@ import java.util.function.Consumer import java.util.stream.Collector import java.util.stream.Stream import java.util.stream.StreamSupport -import kotlin.coroutines.experimental.CoroutineContext +import kotlin.coroutines.experimental.* /** * Creates a [ProducerJob] to read all element of the [Stream]. */ -public fun Stream.asReceiveChannel(context: CoroutineContext = DefaultDispatcher): ReceiveChannel = +public fun Stream.asReceiveChannel(context: CoroutineContext = EmptyCoroutineContext): ReceiveChannel = GlobalScope.produce(context) { for (element in this@asReceiveChannel) send(element) diff --git a/integration/kotlinx-coroutines-jdk8/src/future/Future.kt b/integration/kotlinx-coroutines-jdk8/src/future/Future.kt index 0250d4fae2..ebb1c84bb3 100644 --- a/integration/kotlinx-coroutines-jdk8/src/future/Future.kt +++ b/integration/kotlinx-coroutines-jdk8/src/future/Future.kt @@ -11,11 +11,10 @@ import kotlin.coroutines.experimental.* /** * Starts new coroutine and returns its result as an implementation of [CompletableFuture]. - * * The running coroutine is cancelled when the resulting future is cancelled or otherwise completed. * * Coroutine context is inherited from a [CoroutineScope], additional context elements can be specified with [context] argument. - * If the context does not have any dispatcher nor any other [ContinuationInterceptor], then [DefaultDispatcher] is used. + * If the context does not have any dispatcher nor any other [ContinuationInterceptor], then [Dispatchers.Default] is used. * The parent job is inherited from a [CoroutineScope] as well, but it can also be overridden * with corresponding [coroutineContext] element. * @@ -27,13 +26,13 @@ import kotlin.coroutines.experimental.* * * See [newCoroutineContext][CoroutineScope.newCoroutineContext] for a description of debugging facilities that are available for newly created coroutine. * - * @param context context of the coroutine. The default value is [DefaultDispatcher]. + * @param context additional to [CoroutineScope.coroutineContext] context of the coroutine. * @param start coroutine start option. The default value is [CoroutineStart.DEFAULT]. * @param onCompletion optional completion handler for the coroutine (see [Job.invokeOnCompletion]). * @param block the coroutine code. */ public fun CoroutineScope.future( - context: CoroutineContext = DefaultDispatcher, + context: CoroutineContext = Dispatchers.Default, start: CoroutineStart = CoroutineStart.DEFAULT, onCompletion: CompletionHandler? = null, block: suspend CoroutineScope.() -> T @@ -59,7 +58,7 @@ public fun CoroutineScope.future( imports = ["kotlinx.coroutines.experimental.GlobalScope", "kotlinx.coroutines.experimental.future.future"]) ) public fun future( - context: CoroutineContext = DefaultDispatcher, + context: CoroutineContext = Dispatchers.Default, start: CoroutineStart = CoroutineStart.DEFAULT, onCompletion: CompletionHandler? = null, block: suspend CoroutineScope.() -> T @@ -76,7 +75,7 @@ public fun future( imports = ["kotlinx.coroutines.experimental.GlobalScope", "kotlinx.coroutines.experimental.future.future"]) ) public fun future( - context: CoroutineContext = DefaultDispatcher, + context: CoroutineContext = Dispatchers.Default, start: CoroutineStart = CoroutineStart.DEFAULT, parent: Job? = null, onCompletion: CompletionHandler? = null, @@ -87,16 +86,17 @@ public fun future( /** @suppress **Deprecated**: Binary compatibility */ @Deprecated(message = "Binary compatibility", level = DeprecationLevel.HIDDEN) public fun future( - context: CoroutineContext = DefaultDispatcher, + context: CoroutineContext = Dispatchers.Default, start: CoroutineStart = CoroutineStart.DEFAULT, parent: Job? = null, block: suspend CoroutineScope.() -> T -): CompletableFuture = future(context, start, parent, block = block) +): CompletableFuture = + GlobalScope.future(context + (parent ?: EmptyCoroutineContext), start, block = block) /** @suppress **Deprecated**: Binary compatibility */ @Deprecated(message = "Binary compatibility", level = DeprecationLevel.HIDDEN) public fun future( - context: CoroutineContext = DefaultDispatcher, + context: CoroutineContext = Dispatchers.Default, start: CoroutineStart = CoroutineStart.DEFAULT, block: suspend CoroutineScope.() -> T ): CompletableFuture = @@ -171,7 +171,7 @@ public suspend fun CompletableFuture.await(): T = * * This suspending function is cancellable. * If the [Job] of the current coroutine is cancelled or completed while this suspending function is waiting, this function - * stops waiting for the completion stage and immediately resumes with [CancellationException]. + * stops waiting for the completion stage and immediately resumes with [CancellationException][kotlinx.coroutines.experimental.CancellationException]. * * Note, that `CompletionStage` implementation does not support prompt removal of installed listeners, so on cancellation of this wait * a few small objects will remain in the `CompletionStage` stack of completion actions until it completes itself. @@ -231,7 +231,7 @@ public fun Deferred.toCompletableFuture(): CompletableFuture = asCompl @Suppress("DeprecatedCallableAddReplaceWith") // todo: the warning is incorrectly shown, see KT-17917 @Deprecated("Use the other version. This one is for binary compatibility only.", level=DeprecationLevel.HIDDEN) public fun future( - context: CoroutineContext = DefaultDispatcher, + context: CoroutineContext = Dispatchers.Default, block: suspend () -> T ): CompletableFuture = GlobalScope.future(context = context, block = { block() }) diff --git a/integration/kotlinx-coroutines-slf4j/test/MDCContextTest.kt b/integration/kotlinx-coroutines-slf4j/test/MDCContextTest.kt index b5f0df4371..ee745a4efc 100644 --- a/integration/kotlinx-coroutines-slf4j/test/MDCContextTest.kt +++ b/integration/kotlinx-coroutines-slf4j/test/MDCContextTest.kt @@ -54,7 +54,7 @@ class MDCContextTest : TestBase() { withContext(MDCContext()) { MDC.put("myKey", "myValue2") // Scoped launch with inherited MDContext element - launch(DefaultDispatcher) { + launch(Dispatchers.Default) { assertEquals("myValue", MDC.get("myKey")) expect(2) }.join() @@ -100,7 +100,7 @@ class MDCContextTest : TestBase() { fun testContextWithContext() = runTest { MDC.put("myKey", "myValue") val mainDispatcher = kotlin.coroutines.experimental.coroutineContext[ContinuationInterceptor]!! - withContext(DefaultDispatcher + MDCContext()) { + withContext(Dispatchers.Default + MDCContext()) { assertEquals("myValue", MDC.get("myKey")) withContext(mainDispatcher) { assertEquals("myValue", MDC.get("myKey")) diff --git a/js/kotlinx-coroutines-core-js/README.md b/js/kotlinx-coroutines-core-js/README.md index 94841c6bb1..caad05b610 100644 --- a/js/kotlinx-coroutines-core-js/README.md +++ b/js/kotlinx-coroutines-core-js/README.md @@ -68,7 +68,6 @@ helper function. [NonCancellable] job object is provided to suppress cancellatio [Deferred]: https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines.experimental/-deferred/index.html [CoroutineDispatcher]: https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines.experimental/-coroutine-dispatcher/index.html [DefaultDispatcher]: https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines.experimental/-default-dispatcher.html -[Unconfined]: https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines.experimental/-unconfined/index.html [NonCancellable]: https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines.experimental/-non-cancellable/index.html [CoroutineExceptionHandler]: https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines.experimental/-coroutine-exception-handler/index.html [delay]: https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines.experimental/delay.html diff --git a/js/kotlinx-coroutines-core-js/src/CoroutineContext.kt b/js/kotlinx-coroutines-core-js/src/CoroutineContext.kt index bc065c07f4..a3e9f6457d 100644 --- a/js/kotlinx-coroutines-core-js/src/CoroutineContext.kt +++ b/js/kotlinx-coroutines-core-js/src/CoroutineContext.kt @@ -10,8 +10,19 @@ import kotlin.coroutines.experimental.* private external val navigator: dynamic private const val UNDEFINED = "undefined" -@Suppress("PropertyName", "UnsafeCastFromDynamic") -public actual val DefaultDispatcher: CoroutineDispatcher = when { +/** + * The default [CoroutineDispatcher] that is used by all standard builders. + * @suppress **Deprecated**: Use [Dispatchers.Default]. + */ +@Suppress("PropertyName") +@Deprecated( + message = "Use Dispatchers.Default", + replaceWith = ReplaceWith("Dispatchers.Default", + imports = ["kotlinx.coroutines.experimental.Dispatchers"])) +public actual val DefaultDispatcher: CoroutineDispatcher + get() = Dispatchers.Default + +internal actual fun createDefaultDispatcher(): CoroutineDispatcher = when { // Check if we are running under ReactNative. We have to use NodeDispatcher under it. // The problem is that ReactNative has a `window` object with `addEventListener`, but it does not really work. // For details see https://github.com/Kotlin/kotlinx.coroutines/issues/236 @@ -25,12 +36,13 @@ public actual val DefaultDispatcher: CoroutineDispatcher = when { else -> NodeDispatcher() } -internal actual val DefaultDelay: Delay = DefaultDispatcher as Delay +internal actual val DefaultDelay: Delay + get() = Dispatchers.Default as Delay public actual fun CoroutineScope.newCoroutineContext(context: CoroutineContext): CoroutineContext { val combined = coroutineContext + context - return if (combined !== DefaultDispatcher && combined[ContinuationInterceptor] == null) - combined + DefaultDispatcher else combined + return if (combined !== Dispatchers.Default && combined[ContinuationInterceptor] == null) + combined + Dispatchers.Default else combined } // No debugging facilities on JS diff --git a/js/kotlinx-coroutines-core-js/src/Promise.kt b/js/kotlinx-coroutines-core-js/src/Promise.kt index 4452a2a802..929cd70d4b 100644 --- a/js/kotlinx-coroutines-core-js/src/Promise.kt +++ b/js/kotlinx-coroutines-core-js/src/Promise.kt @@ -11,20 +11,20 @@ import kotlin.js.* * Starts new coroutine and returns its result as an implementation of [Promise]. * * Coroutine context is inherited from a [CoroutineScope], additional context elements can be specified with [context] argument. - * If the context does not have any dispatcher nor any other [ContinuationInterceptor], then [DefaultDispatcher] is used. + * If the context does not have any dispatcher nor any other [ContinuationInterceptor], then [Dispatchers.Default] is used. * The parent job is inherited from a [CoroutineScope] as well, but it can also be overridden * with corresponding [coroutineContext] element. * * By default, the coroutine is immediately scheduled for execution. * Other options can be specified via `start` parameter. See [CoroutineStart] for details. * - * @param context context of the coroutine. The default value is [DefaultDispatcher]. + * @param context additional to [CoroutineScope.coroutineContext] context of the coroutine. * @param start coroutine start option. The default value is [CoroutineStart.DEFAULT]. * @param onCompletion optional completion handler for the coroutine (see [Job.invokeOnCompletion]). * @param block the coroutine code. */ public fun CoroutineScope.promise( - context: CoroutineContext = DefaultDispatcher, + context: CoroutineContext = EmptyCoroutineContext, start: CoroutineStart = CoroutineStart.DEFAULT, onCompletion: CompletionHandler? = null, block: suspend CoroutineScope.() -> T @@ -41,7 +41,7 @@ public fun CoroutineScope.promise( imports = ["kotlinx.coroutines.experimental.*"]) ) public fun promise( - context: CoroutineContext = DefaultDispatcher, + context: CoroutineContext = Dispatchers.Default, start: CoroutineStart = CoroutineStart.DEFAULT, onCompletion: CompletionHandler? = null, block: suspend CoroutineScope.() -> T @@ -58,7 +58,7 @@ public fun promise( imports = ["kotlinx.coroutines.experimental.*"]) ) public fun promise( - context: CoroutineContext = DefaultDispatcher, + context: CoroutineContext = Dispatchers.Default, start: CoroutineStart = CoroutineStart.DEFAULT, parent: Job? = null, onCompletion: CompletionHandler? = null, diff --git a/native/kotlinx-coroutines-core-native/README.md b/native/kotlinx-coroutines-core-native/README.md index 0f1bb0c9e2..68643c98f5 100644 --- a/native/kotlinx-coroutines-core-native/README.md +++ b/native/kotlinx-coroutines-core-native/README.md @@ -71,7 +71,6 @@ helper function. [NonCancellable] job object is provided to suppress cancellatio [runBlocking]: https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines.experimental/run-blocking.html [CoroutineDispatcher]: https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines.experimental/-coroutine-dispatcher/index.html [DefaultDispatcher]: https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines.experimental/-default-dispatcher.html -[Unconfined]: https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines.experimental/-unconfined/index.html [NonCancellable]: https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines.experimental/-non-cancellable/index.html [CoroutineExceptionHandler]: https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines.experimental/-coroutine-exception-handler/index.html [delay]: https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines.experimental/delay.html diff --git a/native/kotlinx-coroutines-core-native/src/CoroutineContext.kt b/native/kotlinx-coroutines-core-native/src/CoroutineContext.kt index c90e23aae3..6fca7ffabe 100644 --- a/native/kotlinx-coroutines-core-native/src/CoroutineContext.kt +++ b/native/kotlinx-coroutines-core-native/src/CoroutineContext.kt @@ -34,10 +34,19 @@ internal object DefaultExecutor : CoroutineDispatcher(), Delay { } /** - * This is the default [CoroutineDispatcher] that is used by all standard builders like - * [launch], [async], etc if no dispatcher nor any other [ContinuationInterceptor] is specified in their context. + * The default [CoroutineDispatcher] that is used by all standard builders. + * @suppress **Deprecated**: Use [Dispatchers.Default]. */ -public actual val DefaultDispatcher: CoroutineDispatcher = DefaultExecutor +@Suppress("PropertyName") +@Deprecated( + message = "Use Dispatchers.Default", + replaceWith = ReplaceWith("Dispatchers.Default", + imports = ["kotlinx.coroutines.experimental.Dispatchers"])) +public actual val DefaultDispatcher: CoroutineDispatcher + get() = Dispatchers.Default + +internal actual fun createDefaultDispatcher(): CoroutineDispatcher = + DefaultExecutor internal actual val DefaultDelay: Delay = DefaultExecutor diff --git a/reactive/coroutines-guide-reactive.md b/reactive/coroutines-guide-reactive.md index eb14e80fd8..e706235dba 100644 --- a/reactive/coroutines-guide-reactive.md +++ b/reactive/coroutines-guide-reactive.md @@ -432,7 +432,7 @@ fun main(args: Array) = runBlocking { subject.onNext("one") subject.onNext("two") // now launch a coroutine to print everything - GlobalScope.launch(Unconfined) { // launch coroutine in unconfined context + GlobalScope.launch(Dispatchers.Unconfined) { // launch coroutine in unconfined context subject.consumeEach { println(it) } } subject.onNext("three") @@ -452,7 +452,7 @@ four -Here we use [Unconfined] coroutine context to launch consuming coroutine with the same behaviour as subscription in Rx. +Here we use [Dispatchers.Unconfined] coroutine context to launch consuming coroutine with the same behaviour as subscription in Rx. It basically means that the launched coroutine is going to be immediately executed in the same thread that is emitting elements. Contexts are covered in more details in a [separate section](#coroutine-context). @@ -582,8 +582,8 @@ It is straightforward to use from a coroutine: ```kotlin fun main(args: Array) = runBlocking { - // Range inherits parent job from runBlocking, but overrides dispatcher with DefaultDispatcher - range(DefaultDispatcher, 1, 5).consumeEach { println(it) } + // Range inherits parent job from runBlocking, but overrides dispatcher with Dispatchers.Default + range(Dispatchers.Default, 1, 5).consumeEach { println(it) } } ``` @@ -996,9 +996,9 @@ Most Rx operators do not have any specific thread (scheduler) associated with th in whatever thread that they happen to be invoked in. We've seen it on the example of `subscribe` operator in the [threads with Rx](#threads-with-rx) section. -In the world of coroutines, [Unconfined] context serves a similar role. Let us modify our previous example, +In the world of coroutines, [Dispatchers.Unconfined] context serves a similar role. Let us modify our previous example, but instead of iterating over the source `Flowable` from the `runBlocking` coroutine that is confined -to the main thread, we launch a new coroutine in `Unconfined` context, while the main coroutine +to the main thread, we launch a new coroutine in `Dispatchers.Unconfined` context, while the main coroutine simply waits its completion using [Job.join]: -Note, that [Unconfined] context shall be used with care. It may improve the overall performance on certain tests, +Note, that [Dispatchers.Unconfined] context shall be used with care. It may improve the overall performance on certain tests, due to the increased stack-locality of operations and less scheduling overhead, but it also produces deeper stacks and makes it harder to reason about asynchronicity of the code that is using it. If a coroutine sends an element to a channel, then the thread that invoked the -[send][SendChannel.send] may start executing the code of a coroutine with [Unconfined] dispatcher. +[send][SendChannel.send] may start executing the code of a coroutine with [Dispatchers.Unconfined] dispatcher. The original producer coroutine that invoked `send` is paused until the unconfined consumer coroutine hits its next suspension point. This is very similar to a lock-step single-threaded `onNext` execution in Rx world in the absense of thread-shifting operators. It is a normal default for Rx, because operators are usually doing very small chunks @@ -1055,10 +1055,9 @@ coroutines for complex pipelines with fan-in and fan-out between multiple worker [runBlocking]: https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines.experimental/run-blocking.html -[Unconfined]: https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines.experimental/-unconfined/index.html +[Dispatchers.Unconfined]: https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines.experimental/-dispatchers/-unconfined.html [yield]: https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines.experimental/yield.html [launch]: https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines.experimental/launch.html -[CommonPool]: https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines.experimental/-common-pool/index.html [Job.join]: https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines.experimental/-job/join.html [Channel]: https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines.experimental.channels/-channel/index.html diff --git a/reactive/kotlinx-coroutines-reactive/src/Convert.kt b/reactive/kotlinx-coroutines-reactive/src/Convert.kt index 09fd37a110..5fa826a978 100644 --- a/reactive/kotlinx-coroutines-reactive/src/Convert.kt +++ b/reactive/kotlinx-coroutines-reactive/src/Convert.kt @@ -17,7 +17,7 @@ import kotlin.coroutines.experimental.* * * @param context -- the coroutine context from which the resulting observable is going to be signalled */ -public fun ReceiveChannel.asPublisher(context: CoroutineContext = DefaultDispatcher): Publisher = GlobalScope.publish(context) { +public fun ReceiveChannel.asPublisher(context: CoroutineContext = EmptyCoroutineContext): Publisher = GlobalScope.publish(context) { for (t in this@asPublisher) send(t) } diff --git a/reactive/kotlinx-coroutines-reactive/src/Publish.kt b/reactive/kotlinx-coroutines-reactive/src/Publish.kt index e45f021e56..7222208dc4 100644 --- a/reactive/kotlinx-coroutines-reactive/src/Publish.kt +++ b/reactive/kotlinx-coroutines-reactive/src/Publish.kt @@ -27,7 +27,7 @@ import kotlin.coroutines.experimental.* * | Failure with exception or `close` with cause | `onError` * * Coroutine context is inherited from a [CoroutineScope], additional context elements can be specified with [context] argument. - * If the context does not have any dispatcher nor any other [ContinuationInterceptor], then [DefaultDispatcher] is used. + * If the context does not have any dispatcher nor any other [ContinuationInterceptor], then [Dispatchers.Default] is used. * The parent job is inherited from a [CoroutineScope] as well, but it can also be overridden * with corresponding [coroutineContext] element. * @@ -54,7 +54,7 @@ public fun CoroutineScope.publish( imports = ["kotlinx.coroutines.experimental.GlobalScope", "kotlinx.coroutines.experimental.reactive.publish"]) ) public fun publish( - context: CoroutineContext = DefaultDispatcher, + context: CoroutineContext = Dispatchers.Default, parent: Job? = null, block: suspend ProducerScope.() -> Unit ): Publisher = GlobalScope.publish(context + (parent ?: EmptyCoroutineContext), block) diff --git a/reactive/kotlinx-coroutines-reactive/test/IntegrationTest.kt b/reactive/kotlinx-coroutines-reactive/test/IntegrationTest.kt index 34b8ea5d8d..b95843af2a 100644 --- a/reactive/kotlinx-coroutines-reactive/test/IntegrationTest.kt +++ b/reactive/kotlinx-coroutines-reactive/test/IntegrationTest.kt @@ -21,8 +21,8 @@ class IntegrationTest( enum class Ctx { MAIN { override fun invoke(context: CoroutineContext): CoroutineContext = context }, - DEFAULT { override fun invoke(context: CoroutineContext): CoroutineContext = DefaultDispatcher }, - UNCONFINED { override fun invoke(context: CoroutineContext): CoroutineContext = Unconfined }; + DEFAULT { override fun invoke(context: CoroutineContext): CoroutineContext = Dispatchers.Default }, + UNCONFINED { override fun invoke(context: CoroutineContext): CoroutineContext = Dispatchers.Unconfined }; abstract operator fun invoke(context: CoroutineContext): CoroutineContext } diff --git a/reactive/kotlinx-coroutines-reactive/test/PublisherCompletionStressTest.kt b/reactive/kotlinx-coroutines-reactive/test/PublisherCompletionStressTest.kt index 7dbf0a3aa8..742cb7d1d1 100644 --- a/reactive/kotlinx-coroutines-reactive/test/PublisherCompletionStressTest.kt +++ b/reactive/kotlinx-coroutines-reactive/test/PublisherCompletionStressTest.kt @@ -24,7 +24,7 @@ class PublisherCompletionStressTest : TestBase() { runBlocking { withTimeout(5000) { var received = 0 - range(DefaultDispatcher, 1, count).consumeEach { x -> + range(Dispatchers.Default, 1, count).consumeEach { x -> received++ if (x != received) error("$x != $received") } diff --git a/reactive/kotlinx-coroutines-reactive/test/PublisherMultiTest.kt b/reactive/kotlinx-coroutines-reactive/test/PublisherMultiTest.kt index 2dcb84cd04..35d365ff38 100644 --- a/reactive/kotlinx-coroutines-reactive/test/PublisherMultiTest.kt +++ b/reactive/kotlinx-coroutines-reactive/test/PublisherMultiTest.kt @@ -13,7 +13,7 @@ class PublisherMultiTest : TestBase() { @Test fun testConcurrentStress() = runBlocking { val n = 10_000 * stressTestMultiplier - val observable = publish(DefaultDispatcher) { + val observable = GlobalScope.publish { // concurrent emitters (many coroutines) val jobs = List(n) { // launch diff --git a/reactive/kotlinx-coroutines-reactor/src/Convert.kt b/reactive/kotlinx-coroutines-reactor/src/Convert.kt index 03366d0a92..822a64a089 100644 --- a/reactive/kotlinx-coroutines-reactor/src/Convert.kt +++ b/reactive/kotlinx-coroutines-reactor/src/Convert.kt @@ -18,7 +18,7 @@ import kotlin.coroutines.experimental.* * * @param context -- the coroutine context from which the resulting mono is going to be signalled */ -public fun Job.asMono(context: CoroutineContext = DefaultDispatcher): Mono = GlobalScope.mono(context) { this@asMono.join() } +public fun Job.asMono(context: CoroutineContext = EmptyCoroutineContext): Mono = GlobalScope.mono(context) { this@asMono.join() } /** * Converts this deferred value to the hot reactive mono that signals @@ -29,7 +29,7 @@ public fun Job.asMono(context: CoroutineContext = DefaultDispatcher): Mono * * @param context -- the coroutine context from which the resulting mono is going to be signalled */ -public fun Deferred.asMono(context: CoroutineContext = DefaultDispatcher): Mono = GlobalScope.mono(context) { this@asMono.await() } +public fun Deferred.asMono(context: CoroutineContext = EmptyCoroutineContext): Mono = GlobalScope.mono(context) { this@asMono.await() } /** * Converts a stream of elements received from the channel to the hot reactive flux. @@ -39,7 +39,7 @@ public fun Deferred.asMono(context: CoroutineContext = DefaultDispatcher * * @param context -- the coroutine context from which the resulting flux is going to be signalled */ -public fun ReceiveChannel.asFlux(context: CoroutineContext = DefaultDispatcher): Flux = GlobalScope.flux(context) { +public fun ReceiveChannel.asFlux(context: CoroutineContext = EmptyCoroutineContext): Flux = GlobalScope.flux(context) { for (t in this@asFlux) send(t) } \ No newline at end of file diff --git a/reactive/kotlinx-coroutines-reactor/src/Flux.kt b/reactive/kotlinx-coroutines-reactor/src/Flux.kt index a21939f0f6..73e1a6a580 100644 --- a/reactive/kotlinx-coroutines-reactor/src/Flux.kt +++ b/reactive/kotlinx-coroutines-reactor/src/Flux.kt @@ -16,7 +16,7 @@ import kotlin.coroutines.experimental.* * Coroutine emits items with `send`. Unsubscribing cancels running coroutine. * * Coroutine context is inherited from a [CoroutineScope], additional context elements can be specified with [context] argument. - * If the context does not have any dispatcher nor any other [ContinuationInterceptor], then [DefaultDispatcher] is used. + * If the context does not have any dispatcher nor any other [ContinuationInterceptor], then [Dispatchers.Default] is used. * The parent job is inherited from a [CoroutineScope] as well, but it can also be overridden * with corresponding [coroutineContext] element. * @@ -30,9 +30,10 @@ import kotlin.coroutines.experimental.* * | Failure with exception or `close` with cause | `onError` */ fun CoroutineScope.flux( - context: CoroutineContext = EmptyCoroutineContext, - block: suspend ProducerScope.() -> Unit -): Flux = Flux.from(publish(newCoroutineContext(context), block = block)) + context: CoroutineContext = EmptyCoroutineContext, + block: suspend ProducerScope.() -> Unit +): Flux = + Flux.from(publish(newCoroutineContext(context), block = block)) /** @@ -40,12 +41,15 @@ fun CoroutineScope.flux( * @suppress **Deprecated** Use [CoroutineScope.mono] instead. */ @Deprecated( - message = "Standalone coroutine builders are deprecated, use extensions on CoroutineScope instead", - replaceWith = ReplaceWith("GlobalScope.flux(context, block)", - imports = ["kotlinx.coroutines.experimental.GlobalScope", "kotlinx.coroutines.experimental.reactor.flux"]) + message = "Standalone coroutine builders are deprecated, use extensions on CoroutineScope instead", + replaceWith = ReplaceWith( + "GlobalScope.flux(context, block)", + imports = ["kotlinx.coroutines.experimental.GlobalScope", "kotlinx.coroutines.experimental.reactor.flux"] + ) ) @JvmOverloads // for binary compatibility with older code compiled before context had a default fun flux( - context: CoroutineContext = DefaultDispatcher, - block: suspend ProducerScope.() -> Unit -): Flux = GlobalScope.flux(context, block) + context: CoroutineContext = Dispatchers.Default, + block: suspend ProducerScope.() -> Unit +): Flux = + GlobalScope.flux(context, block) diff --git a/reactive/kotlinx-coroutines-reactor/src/Mono.kt b/reactive/kotlinx-coroutines-reactor/src/Mono.kt index 5cc0742d07..65e2c747c7 100644 --- a/reactive/kotlinx-coroutines-reactor/src/Mono.kt +++ b/reactive/kotlinx-coroutines-reactor/src/Mono.kt @@ -20,11 +20,11 @@ import kotlin.coroutines.experimental.* * | Failure with exception or unsubscribe | `error` * * Coroutine context is inherited from a [CoroutineScope], additional context elements can be specified with [context] argument. - * If the context does not have any dispatcher nor any other [ContinuationInterceptor], then [DefaultDispatcher] is used. + * If the context does not have any dispatcher nor any other [ContinuationInterceptor], then [Dispatchers.Default] is used. * The parent job is inherited from a [CoroutineScope] as well, but it can also be overridden * with corresponding [coroutineContext] element. * - * @param context context of the coroutine.. + * @param context context of the coroutine. * @param block the coroutine code. */ fun CoroutineScope.mono( @@ -47,10 +47,11 @@ fun CoroutineScope.mono( imports = ["kotlinx.coroutines.experimental.GlobalScope", "kotlinx.coroutines.experimental.reactor.mono"]) ) fun mono( - context: CoroutineContext = DefaultDispatcher, + context: CoroutineContext = Dispatchers.Default, parent: Job? = null, block: suspend CoroutineScope.() -> T? -): Mono = GlobalScope.mono(context + (parent ?: EmptyCoroutineContext), block) +): Mono = + GlobalScope.mono(context + (parent ?: EmptyCoroutineContext), block) private class MonoCoroutine( parentContext: CoroutineContext, diff --git a/reactive/kotlinx-coroutines-reactor/test/ConvertTest.kt b/reactive/kotlinx-coroutines-reactor/test/ConvertTest.kt index ee80cb91e2..f22446e67a 100644 --- a/reactive/kotlinx-coroutines-reactor/test/ConvertTest.kt +++ b/reactive/kotlinx-coroutines-reactor/test/ConvertTest.kt @@ -51,11 +51,11 @@ class ConvertTest : TestBase() { delay(50) "OK" } - val mono1 = d.asMono(Unconfined) + val mono1 = d.asMono(Dispatchers.Unconfined) checkMonoValue(mono1) { assertEquals("OK", it) } - val mono2 = d.asMono(Unconfined) + val mono2 = d.asMono(Dispatchers.Unconfined) checkMonoValue(mono2) { assertEquals("OK", it) } @@ -67,9 +67,9 @@ class ConvertTest : TestBase() { delay(50) null } - val mono1 = d.asMono(Unconfined) + val mono1 = d.asMono(Dispatchers.Unconfined) checkMonoValue(mono1, ::assertNull) - val mono2 = d.asMono(Unconfined) + val mono2 = d.asMono(Dispatchers.Unconfined) checkMonoValue(mono2, ::assertNull) } @@ -79,11 +79,11 @@ class ConvertTest : TestBase() { delay(50) throw TestException("OK") } - val mono1 = d.asMono(Unconfined) + val mono1 = d.asMono(Dispatchers.Unconfined) checkErroneous(mono1) { check(it is TestException && it.message == "OK") { "$it" } } - val mono2 = d.asMono(Unconfined) + val mono2 = d.asMono(Dispatchers.Unconfined) checkErroneous(mono2) { check(it is TestException && it.message == "OK") { "$it" } } @@ -97,7 +97,7 @@ class ConvertTest : TestBase() { delay(50) send("K") } - val flux = c.asFlux(Unconfined) + val flux = c.asFlux(Dispatchers.Unconfined) checkMonoValue(flux.reduce { t1, t2 -> t1 + t2 }) { assertEquals("OK", it) } @@ -111,8 +111,8 @@ class ConvertTest : TestBase() { delay(50) throw TestException("K") } - val flux = c.asFlux(Unconfined) - val mono = GlobalScope.mono(Unconfined) { + val flux = c.asFlux(Dispatchers.Unconfined) + val mono = GlobalScope.mono(Dispatchers.Unconfined) { var result = "" try { flux.consumeEach { result += it } diff --git a/reactive/kotlinx-coroutines-reactor/test/FluxCompletionStressTest.kt b/reactive/kotlinx-coroutines-reactor/test/FluxCompletionStressTest.kt index 1c9bf2eeca..7188afa452 100644 --- a/reactive/kotlinx-coroutines-reactor/test/FluxCompletionStressTest.kt +++ b/reactive/kotlinx-coroutines-reactor/test/FluxCompletionStressTest.kt @@ -25,7 +25,7 @@ class FluxCompletionStressTest : TestBase() { runBlocking { withTimeout(5000) { var received = 0 - range(DefaultDispatcher, 1, count).consumeEach { x -> + range(Dispatchers.Default, 1, count).consumeEach { x -> received++ if (x != received) error("$x != $received") } diff --git a/reactive/kotlinx-coroutines-reactor/test/FluxMultiTest.kt b/reactive/kotlinx-coroutines-reactor/test/FluxMultiTest.kt index 6f4411bd5b..49d46cc0a3 100644 --- a/reactive/kotlinx-coroutines-reactor/test/FluxMultiTest.kt +++ b/reactive/kotlinx-coroutines-reactor/test/FluxMultiTest.kt @@ -45,7 +45,7 @@ class FluxMultiTest : TestBase() { @Test fun testIteratorResendUnconfined() { val n = 10_000 * stressTestMultiplier - val flux = GlobalScope.flux(Unconfined) { + val flux = GlobalScope.flux(Dispatchers.Unconfined) { Flux.range(0, n).consumeEach { send(it) } } checkMonoValue(flux.collectList()) { list -> diff --git a/reactive/kotlinx-coroutines-rx1/src/RxCompletable.kt b/reactive/kotlinx-coroutines-rx1/src/RxCompletable.kt index 5e2ee7582f..2694d5a4cf 100644 --- a/reactive/kotlinx-coroutines-rx1/src/RxCompletable.kt +++ b/reactive/kotlinx-coroutines-rx1/src/RxCompletable.kt @@ -19,11 +19,11 @@ import kotlin.coroutines.experimental.* * | Failure with exception or unsubscribe | `onError` * * Coroutine context is inherited from a [CoroutineScope], additional context elements can be specified with [context] argument. - * If the context does not have any dispatcher nor any other [ContinuationInterceptor], then [DefaultDispatcher] is used. + * If the context does not have any dispatcher nor any other [ContinuationInterceptor], then [Dispatchers.Default] is used. * The parent job is inherited from a [CoroutineScope] as well, but it can also be overridden * with corresponding [coroutineContext] element. * - * @param context context of the coroutine.. + * @param context context of the coroutine. * @param block the coroutine code. */ public fun CoroutineScope.rxCompletable( @@ -46,7 +46,7 @@ public fun CoroutineScope.rxCompletable( imports = ["kotlinx.coroutines.experimental.GlobalScope", "kotlinx.coroutines.experimental.rx1.rxCompletable"]) ) public fun rxCompletable( - context: CoroutineContext = DefaultDispatcher, + context: CoroutineContext = Dispatchers.Default, parent: Job? = null, block: suspend CoroutineScope.() -> Unit ): Completable = GlobalScope.rxCompletable(context + (parent ?: EmptyCoroutineContext), block) diff --git a/reactive/kotlinx-coroutines-rx1/src/RxObservable.kt b/reactive/kotlinx-coroutines-rx1/src/RxObservable.kt index 2cc646d735..cd9787a271 100644 --- a/reactive/kotlinx-coroutines-rx1/src/RxObservable.kt +++ b/reactive/kotlinx-coroutines-rx1/src/RxObservable.kt @@ -27,7 +27,7 @@ import kotlin.coroutines.experimental.* * | Failure with exception or `close` with cause | `onError` * * Coroutine context is inherited from a [CoroutineScope], additional context elements can be specified with [context] argument. - * If the context does not have any dispatcher nor any other [ContinuationInterceptor], then [DefaultDispatcher] is used. + * If the context does not have any dispatcher nor any other [ContinuationInterceptor], then [Dispatchers.Default] is used. * The parent job is inherited from a [CoroutineScope] as well, but it can also be overridden * with corresponding [coroutineContext] element. ** @@ -55,7 +55,7 @@ public fun CoroutineScope.rxObservable( imports = ["kotlinx.coroutines.experimental.GlobalScope", "kotlinx.coroutines.experimental.rx1.rxObservable"]) ) public fun rxObservable( - context: CoroutineContext = DefaultDispatcher, + context: CoroutineContext = Dispatchers.Default, parent: Job? = null, block: suspend ProducerScope.() -> Unit ): Observable = GlobalScope.rxObservable(context + (parent ?: EmptyCoroutineContext), block) diff --git a/reactive/kotlinx-coroutines-rx1/src/RxSingle.kt b/reactive/kotlinx-coroutines-rx1/src/RxSingle.kt index 88e7202308..be70ee2583 100644 --- a/reactive/kotlinx-coroutines-rx1/src/RxSingle.kt +++ b/reactive/kotlinx-coroutines-rx1/src/RxSingle.kt @@ -19,7 +19,7 @@ import kotlin.coroutines.experimental.* * | Failure with exception or unsubscribe | `onError` * * Coroutine context is inherited from a [CoroutineScope], additional context elements can be specified with [context] argument. - * If the context does not have any dispatcher nor any other [ContinuationInterceptor], then [DefaultDispatcher] is used. + * If the context does not have any dispatcher nor any other [ContinuationInterceptor], then [Dispatchers.Default] is used. * The parent job is inherited from a [CoroutineScope] as well, but it can also be overridden * with corresponding [coroutineContext] element. * @@ -46,7 +46,7 @@ public fun CoroutineScope.rxSingle( imports = ["kotlinx.coroutines.experimental.GlobalScope", "kotlinx.coroutines.experimental.rx1.rxSingle"]) ) public fun rxSingle( - context: CoroutineContext = DefaultDispatcher, + context: CoroutineContext = Dispatchers.Default, parent: Job? = null, block: suspend CoroutineScope.() -> T ): Single = GlobalScope.rxSingle(context + (parent ?: EmptyCoroutineContext), block) diff --git a/reactive/kotlinx-coroutines-rx1/test/ConvertTest.kt b/reactive/kotlinx-coroutines-rx1/test/ConvertTest.kt index be8b3b4899..cb1f3dcbc6 100644 --- a/reactive/kotlinx-coroutines-rx1/test/ConvertTest.kt +++ b/reactive/kotlinx-coroutines-rx1/test/ConvertTest.kt @@ -50,11 +50,11 @@ class ConvertTest : TestBase() { delay(50) "OK" } - val single1 = d.asSingle(Unconfined) + val single1 = d.asSingle(Dispatchers.Unconfined) checkSingleValue(single1) { assertThat(it, IsEqual("OK")) } - val single2 = d.asSingle(Unconfined) + val single2 = d.asSingle(Dispatchers.Unconfined) checkSingleValue(single2) { assertThat(it, IsEqual("OK")) } @@ -66,12 +66,12 @@ class ConvertTest : TestBase() { delay(50) throw TestException("OK") } - val single1 = d.asSingle(Unconfined) + val single1 = d.asSingle(Dispatchers.Unconfined) checkErroneous(single1) { assertThat(it, IsInstanceOf(TestException::class.java)) assertThat(it.message, IsEqual("OK")) } - val single2 = d.asSingle(Unconfined) + val single2 = d.asSingle(Dispatchers.Unconfined) checkErroneous(single2) { assertThat(it, IsInstanceOf(TestException::class.java)) assertThat(it.message, IsEqual("OK")) @@ -86,7 +86,7 @@ class ConvertTest : TestBase() { delay(50) send("K") } - val observable = c.asObservable(Unconfined) + val observable = c.asObservable(Dispatchers.Unconfined) checkSingleValue(observable.reduce { t1, t2 -> t1 + t2 }) { assertThat(it, IsEqual("OK")) } @@ -100,8 +100,8 @@ class ConvertTest : TestBase() { delay(50) throw TestException("K") } - val observable = c.asObservable(Unconfined) - val single = GlobalScope.rxSingle(Unconfined) { + val observable = c.asObservable(Dispatchers.Unconfined) + val single = GlobalScope.rxSingle(Dispatchers.Unconfined) { var result = "" try { observable.consumeEach { result += it } diff --git a/reactive/kotlinx-coroutines-rx1/test/IntegrationTest.kt b/reactive/kotlinx-coroutines-rx1/test/IntegrationTest.kt index cb1554efd4..6fd24c6f08 100644 --- a/reactive/kotlinx-coroutines-rx1/test/IntegrationTest.kt +++ b/reactive/kotlinx-coroutines-rx1/test/IntegrationTest.kt @@ -20,9 +20,9 @@ class IntegrationTest( ) : TestBase() { enum class Ctx { - MAIN { override fun invoke(context: CoroutineContext): CoroutineContext = context }, - COMMON_POOL { override fun invoke(context: CoroutineContext): CoroutineContext = DefaultDispatcher }, - UNCONFINED { override fun invoke(context: CoroutineContext): CoroutineContext = Unconfined }; + MAIN { override fun invoke(context: CoroutineContext): CoroutineContext = context }, + DEFAULT { override fun invoke(context: CoroutineContext): CoroutineContext = Dispatchers.Default }, + UNCONFINED { override fun invoke(context: CoroutineContext): CoroutineContext = Dispatchers.Unconfined }; abstract operator fun invoke(context: CoroutineContext): CoroutineContext } diff --git a/reactive/kotlinx-coroutines-rx1/test/ObservableCompletionStressTest.kt b/reactive/kotlinx-coroutines-rx1/test/ObservableCompletionStressTest.kt index 64dfac7952..3407465f27 100644 --- a/reactive/kotlinx-coroutines-rx1/test/ObservableCompletionStressTest.kt +++ b/reactive/kotlinx-coroutines-rx1/test/ObservableCompletionStressTest.kt @@ -24,7 +24,7 @@ class ObservableCompletionStressTest : TestBase() { runBlocking { withTimeout(5000) { var received = 0 - range(DefaultDispatcher, 1, count).consumeEach { x -> + range(Dispatchers.Default, 1, count).consumeEach { x -> received++ if (x != received) error("$x != $received") } diff --git a/reactive/kotlinx-coroutines-rx1/test/ObservableMultiTest.kt b/reactive/kotlinx-coroutines-rx1/test/ObservableMultiTest.kt index 8a578f5551..bd3ab2ebfd 100644 --- a/reactive/kotlinx-coroutines-rx1/test/ObservableMultiTest.kt +++ b/reactive/kotlinx-coroutines-rx1/test/ObservableMultiTest.kt @@ -45,9 +45,9 @@ class ObservableMultiTest : TestBase() { } @Test - fun testIteratorResendUnconfined() { + fun testIteratorResendDispatchers() { val n = 10_000 * stressTestMultiplier - val observable = GlobalScope.rxObservable(Unconfined) { + val observable = GlobalScope.rxObservable(Dispatchers.Unconfined) { Observable.range(0, n).consumeEach { send(it) } } checkSingleValue(observable.toList()) { list -> diff --git a/reactive/kotlinx-coroutines-rx2/src/RxCompletable.kt b/reactive/kotlinx-coroutines-rx2/src/RxCompletable.kt index f055575272..50dcb9f649 100644 --- a/reactive/kotlinx-coroutines-rx2/src/RxCompletable.kt +++ b/reactive/kotlinx-coroutines-rx2/src/RxCompletable.kt @@ -20,7 +20,7 @@ import kotlin.coroutines.experimental.* * | Failure with exception or unsubscribe | `onError` * * Coroutine context is inherited from a [CoroutineScope], additional context elements can be specified with [context] argument. - * If the context does not have any dispatcher nor any other [ContinuationInterceptor], then [DefaultDispatcher] is used. + * If the context does not have any dispatcher nor any other [ContinuationInterceptor], then [Dispatchers.Default] is used. * The parent job is inherited from a [CoroutineScope] as well, but it can also be overridden * with corresponding [coroutineContext] element. * @@ -47,7 +47,7 @@ public fun CoroutineScope.rxCompletable( imports = ["kotlinx.coroutines.experimental.GlobalScope", "kotlinx.coroutines.experimental.rx2.rxCompletable"]) ) public fun rxCompletable( - context: CoroutineContext = DefaultDispatcher, + context: CoroutineContext = Dispatchers.Default, parent: Job? = null, block: suspend CoroutineScope.() -> Unit ): Completable = GlobalScope.rxCompletable(context + (parent ?: EmptyCoroutineContext), block) diff --git a/reactive/kotlinx-coroutines-rx2/src/RxFlowable.kt b/reactive/kotlinx-coroutines-rx2/src/RxFlowable.kt index 0818def90e..ad3b53d09b 100644 --- a/reactive/kotlinx-coroutines-rx2/src/RxFlowable.kt +++ b/reactive/kotlinx-coroutines-rx2/src/RxFlowable.kt @@ -25,7 +25,7 @@ import kotlin.coroutines.experimental.* * | Failure with exception or `close` with cause | `onError` * * Coroutine context is inherited from a [CoroutineScope], additional context elements can be specified with [context] argument. - * If the context does not have any dispatcher nor any other [ContinuationInterceptor], then [DefaultDispatcher] is used. + * If the context does not have any dispatcher nor any other [ContinuationInterceptor], then [Dispatchers.Default] is used. * The parent job is inherited from a [CoroutineScope] as well, but it can also be overridden * with corresponding [coroutineContext] element. * @@ -48,6 +48,6 @@ public fun CoroutineScope.rxFlowable( ) @JvmOverloads // for binary compatibility with older code compiled before context had a default public fun rxFlowable( - context: CoroutineContext = DefaultDispatcher, + context: CoroutineContext = Dispatchers.Default, block: suspend ProducerScope.() -> Unit ): Flowable = GlobalScope.rxFlowable(context, block) diff --git a/reactive/kotlinx-coroutines-rx2/src/RxMaybe.kt b/reactive/kotlinx-coroutines-rx2/src/RxMaybe.kt index 935981cbf3..44aee95063 100644 --- a/reactive/kotlinx-coroutines-rx2/src/RxMaybe.kt +++ b/reactive/kotlinx-coroutines-rx2/src/RxMaybe.kt @@ -21,7 +21,7 @@ import kotlin.coroutines.experimental.* * | Failure with exception or unsubscribe | `onError` * * Coroutine context is inherited from a [CoroutineScope], additional context elements can be specified with [context] argument. - * If the context does not have any dispatcher nor any other [ContinuationInterceptor], then [DefaultDispatcher] is used. + * If the context does not have any dispatcher nor any other [ContinuationInterceptor], then [Dispatchers.Default] is used. * The parent job is inherited from a [CoroutineScope] as well, but it can also be overridden * with corresponding [coroutineContext] element. * @@ -48,7 +48,7 @@ public fun CoroutineScope.rxMaybe( imports = ["kotlinx.coroutines.experimental.GlobalScope", "kotlinx.coroutines.experimental.rx2.rxMaybe"]) ) public fun rxMaybe( - context: CoroutineContext = DefaultDispatcher, + context: CoroutineContext = Dispatchers.Default, parent: Job? = null, block: suspend CoroutineScope.() -> T? ): Maybe = GlobalScope.rxMaybe(context + (parent ?: EmptyCoroutineContext), block) diff --git a/reactive/kotlinx-coroutines-rx2/src/RxObservable.kt b/reactive/kotlinx-coroutines-rx2/src/RxObservable.kt index 18f855d068..1744968c9a 100644 --- a/reactive/kotlinx-coroutines-rx2/src/RxObservable.kt +++ b/reactive/kotlinx-coroutines-rx2/src/RxObservable.kt @@ -28,7 +28,7 @@ import kotlin.coroutines.experimental.* * | Failure with exception or `close` with cause | `onError` * * Coroutine context is inherited from a [CoroutineScope], additional context elements can be specified with [context] argument. - * If the context does not have any dispatcher nor any other [ContinuationInterceptor], then [DefaultDispatcher] is used. + * If the context does not have any dispatcher nor any other [ContinuationInterceptor], then [Dispatchers.Default] is used. * The parent job is inherited from a [CoroutineScope] as well, but it can also be overridden * with corresponding [coroutineContext] element. * @@ -55,7 +55,7 @@ public fun CoroutineScope.rxObservable( imports = ["kotlinx.coroutines.experimental.GlobalScope", "kotlinx.coroutines.experimental.rx2.rxObservable"]) ) public fun rxObservable( - context: CoroutineContext = DefaultDispatcher, + context: CoroutineContext = Dispatchers.Default, parent: Job? = null, block: suspend ProducerScope.() -> Unit ): Observable = GlobalScope.rxObservable(context + (parent ?: EmptyCoroutineContext), block) diff --git a/reactive/kotlinx-coroutines-rx2/src/RxSingle.kt b/reactive/kotlinx-coroutines-rx2/src/RxSingle.kt index 20f0091859..00bb9fe914 100644 --- a/reactive/kotlinx-coroutines-rx2/src/RxSingle.kt +++ b/reactive/kotlinx-coroutines-rx2/src/RxSingle.kt @@ -20,7 +20,7 @@ import kotlin.coroutines.experimental.* * | Failure with exception or unsubscribe | `onError` * * Coroutine context is inherited from a [CoroutineScope], additional context elements can be specified with [context] argument. - * If the context does not have any dispatcher nor any other [ContinuationInterceptor], then [DefaultDispatcher] is used. + * If the context does not have any dispatcher nor any other [ContinuationInterceptor], then [Dispatchers.Default] is used. * The parent job is inherited from a [CoroutineScope] as well, but it can also be overridden * with corresponding [coroutineContext] element. * @@ -47,7 +47,7 @@ public fun CoroutineScope.rxSingle( imports = ["kotlinx.coroutines.experimental.GlobalScope", "kotlinx.coroutines.experimental.rx2.rxSingle"]) ) public fun rxSingle( - context: CoroutineContext = DefaultDispatcher, + context: CoroutineContext = Dispatchers.Default, parent: Job? = null, block: suspend CoroutineScope.() -> T ): Single = GlobalScope.rxSingle(context + (parent ?: EmptyCoroutineContext), block) diff --git a/reactive/kotlinx-coroutines-rx2/test/ConvertTest.kt b/reactive/kotlinx-coroutines-rx2/test/ConvertTest.kt index 5284725a1b..aedda13997 100644 --- a/reactive/kotlinx-coroutines-rx2/test/ConvertTest.kt +++ b/reactive/kotlinx-coroutines-rx2/test/ConvertTest.kt @@ -49,11 +49,11 @@ class ConvertTest : TestBase() { delay(50) "OK" } - val maybe1 = d.asMaybe(Unconfined) + val maybe1 = d.asMaybe(Dispatchers.Unconfined) checkMaybeValue(maybe1) { assertEquals("OK", it) } - val maybe2 = d.asMaybe(Unconfined) + val maybe2 = d.asMaybe(Dispatchers.Unconfined) checkMaybeValue(maybe2) { assertEquals("OK", it) } @@ -65,9 +65,9 @@ class ConvertTest : TestBase() { delay(50) null } - val maybe1 = d.asMaybe(Unconfined) + val maybe1 = d.asMaybe(Dispatchers.Unconfined) checkMaybeValue(maybe1, ::assertNull) - val maybe2 = d.asMaybe(Unconfined) + val maybe2 = d.asMaybe(Dispatchers.Unconfined) checkMaybeValue(maybe2, ::assertNull) } @@ -77,11 +77,11 @@ class ConvertTest : TestBase() { delay(50) throw TestException("OK") } - val maybe1 = d.asMaybe(Unconfined) + val maybe1 = d.asMaybe(Dispatchers.Unconfined) checkErroneous(maybe1) { check(it is TestException && it.message == "OK") { "$it" } } - val maybe2 = d.asMaybe(Unconfined) + val maybe2 = d.asMaybe(Dispatchers.Unconfined) checkErroneous(maybe2) { check(it is TestException && it.message == "OK") { "$it" } } @@ -93,11 +93,11 @@ class ConvertTest : TestBase() { delay(50) "OK" } - val single1 = d.asSingle(Unconfined) + val single1 = d.asSingle(Dispatchers.Unconfined) checkSingleValue(single1) { assertEquals("OK", it) } - val single2 = d.asSingle(Unconfined) + val single2 = d.asSingle(Dispatchers.Unconfined) checkSingleValue(single2) { assertEquals("OK", it) } @@ -109,11 +109,11 @@ class ConvertTest : TestBase() { delay(50) throw TestException("OK") } - val single1 = d.asSingle(Unconfined) + val single1 = d.asSingle(Dispatchers.Unconfined) checkErroneous(single1) { check(it is TestException && it.message == "OK") { "$it" } } - val single2 = d.asSingle(Unconfined) + val single2 = d.asSingle(Dispatchers.Unconfined) checkErroneous(single2) { check(it is TestException && it.message == "OK") { "$it" } } @@ -127,7 +127,7 @@ class ConvertTest : TestBase() { delay(50) send("K") } - val observable = c.asObservable(Unconfined) + val observable = c.asObservable(Dispatchers.Unconfined) checkSingleValue(observable.reduce { t1, t2 -> t1 + t2 }.toSingle()) { assertEquals("OK", it) } @@ -141,8 +141,8 @@ class ConvertTest : TestBase() { delay(50) throw TestException("K") } - val observable = c.asObservable(Unconfined) - val single = GlobalScope.rxSingle(Unconfined) { + val observable = c.asObservable(Dispatchers.Unconfined) + val single = GlobalScope.rxSingle(Dispatchers.Unconfined) { var result = "" try { observable.consumeEach { result += it } diff --git a/reactive/kotlinx-coroutines-rx2/test/IntegrationTest.kt b/reactive/kotlinx-coroutines-rx2/test/IntegrationTest.kt index 5e612dce76..e25429a803 100644 --- a/reactive/kotlinx-coroutines-rx2/test/IntegrationTest.kt +++ b/reactive/kotlinx-coroutines-rx2/test/IntegrationTest.kt @@ -21,8 +21,8 @@ class IntegrationTest( enum class Ctx { MAIN { override fun invoke(context: CoroutineContext): CoroutineContext = context }, - DEFAULT { override fun invoke(context: CoroutineContext): CoroutineContext = DefaultDispatcher }, - UNCONFINED { override fun invoke(context: CoroutineContext): CoroutineContext = Unconfined }; + DEFAULT { override fun invoke(context: CoroutineContext): CoroutineContext = Dispatchers.Default }, + UNCONFINED { override fun invoke(context: CoroutineContext): CoroutineContext = Dispatchers.Unconfined }; abstract operator fun invoke(context: CoroutineContext): CoroutineContext } diff --git a/reactive/kotlinx-coroutines-rx2/test/ObservableCompletionStressTest.kt b/reactive/kotlinx-coroutines-rx2/test/ObservableCompletionStressTest.kt index 92ca2f3e43..181d096e93 100644 --- a/reactive/kotlinx-coroutines-rx2/test/ObservableCompletionStressTest.kt +++ b/reactive/kotlinx-coroutines-rx2/test/ObservableCompletionStressTest.kt @@ -24,7 +24,7 @@ class ObservableCompletionStressTest : TestBase() { runBlocking { withTimeout(5000) { var received = 0 - range(DefaultDispatcher, 1, count).consumeEach { x -> + range(Dispatchers.Default, 1, count).consumeEach { x -> received++ if (x != received) error("$x != $received") } diff --git a/reactive/kotlinx-coroutines-rx2/test/ObservableMultiTest.kt b/reactive/kotlinx-coroutines-rx2/test/ObservableMultiTest.kt index 2e0596d866..e7613057ba 100644 --- a/reactive/kotlinx-coroutines-rx2/test/ObservableMultiTest.kt +++ b/reactive/kotlinx-coroutines-rx2/test/ObservableMultiTest.kt @@ -47,7 +47,7 @@ class ObservableMultiTest : TestBase() { @Test fun testIteratorResendUnconfined() { val n = 10_000 * stressTestMultiplier - val observable = GlobalScope.rxObservable(Unconfined) { + val observable = GlobalScope.rxObservable(Dispatchers.Unconfined) { Observable.range(0, n).consumeEach { send(it) } } checkSingleValue(observable.toList()) { list -> diff --git a/reactive/kotlinx-coroutines-rx2/test/guide/example-reactive-basic-01.kt b/reactive/kotlinx-coroutines-rx2/test/guide/example-reactive-basic-01.kt index a80d5dffce..60a4ec5838 100644 --- a/reactive/kotlinx-coroutines-rx2/test/guide/example-reactive-basic-01.kt +++ b/reactive/kotlinx-coroutines-rx2/test/guide/example-reactive-basic-01.kt @@ -7,6 +7,7 @@ package kotlinx.coroutines.experimental.rx2.guide.basic01 import kotlinx.coroutines.experimental.* import kotlinx.coroutines.experimental.channels.* +import kotlin.coroutines.experimental.* fun main(args: Array) = runBlocking { // create a channel that produces numbers from 1 to 3 with 200ms delays between them diff --git a/reactive/kotlinx-coroutines-rx2/test/guide/example-reactive-basic-02.kt b/reactive/kotlinx-coroutines-rx2/test/guide/example-reactive-basic-02.kt index c4d5ee0002..3e59912c7d 100644 --- a/reactive/kotlinx-coroutines-rx2/test/guide/example-reactive-basic-02.kt +++ b/reactive/kotlinx-coroutines-rx2/test/guide/example-reactive-basic-02.kt @@ -7,6 +7,7 @@ package kotlinx.coroutines.experimental.rx2.guide.basic02 import kotlinx.coroutines.experimental.* import kotlinx.coroutines.experimental.reactive.* +import kotlin.coroutines.experimental.* fun main(args: Array) = runBlocking { // create a publisher that produces numbers from 1 to 3 with 200ms delays between them diff --git a/reactive/kotlinx-coroutines-rx2/test/guide/example-reactive-basic-05.kt b/reactive/kotlinx-coroutines-rx2/test/guide/example-reactive-basic-05.kt index 55e98a3ef7..a00118d1df 100644 --- a/reactive/kotlinx-coroutines-rx2/test/guide/example-reactive-basic-05.kt +++ b/reactive/kotlinx-coroutines-rx2/test/guide/example-reactive-basic-05.kt @@ -8,6 +8,7 @@ package kotlinx.coroutines.experimental.rx2.guide.basic05 import io.reactivex.schedulers.* import kotlinx.coroutines.experimental.* import kotlinx.coroutines.experimental.rx2.* +import kotlin.coroutines.experimental.* fun main(args: Array) = runBlocking { // coroutine -- fast producer of elements in the context of the main thread diff --git a/reactive/kotlinx-coroutines-rx2/test/guide/example-reactive-basic-07.kt b/reactive/kotlinx-coroutines-rx2/test/guide/example-reactive-basic-07.kt index 1d14dc1b6d..326f294ba3 100644 --- a/reactive/kotlinx-coroutines-rx2/test/guide/example-reactive-basic-07.kt +++ b/reactive/kotlinx-coroutines-rx2/test/guide/example-reactive-basic-07.kt @@ -14,7 +14,7 @@ fun main(args: Array) = runBlocking { subject.onNext("one") subject.onNext("two") // now launch a coroutine to print everything - GlobalScope.launch(Unconfined) { // launch coroutine in unconfined context + GlobalScope.launch(Dispatchers.Unconfined) { // launch coroutine in unconfined context subject.consumeEach { println(it) } } subject.onNext("three") diff --git a/reactive/kotlinx-coroutines-rx2/test/guide/example-reactive-basic-08.kt b/reactive/kotlinx-coroutines-rx2/test/guide/example-reactive-basic-08.kt index ebfba2c796..ff05731611 100644 --- a/reactive/kotlinx-coroutines-rx2/test/guide/example-reactive-basic-08.kt +++ b/reactive/kotlinx-coroutines-rx2/test/guide/example-reactive-basic-08.kt @@ -8,6 +8,7 @@ package kotlinx.coroutines.experimental.rx2.guide.basic08 import io.reactivex.subjects.* import kotlinx.coroutines.experimental.* import kotlinx.coroutines.experimental.rx2.* +import kotlin.coroutines.experimental.* fun main(args: Array) = runBlocking { val subject = BehaviorSubject.create() diff --git a/reactive/kotlinx-coroutines-rx2/test/guide/example-reactive-basic-09.kt b/reactive/kotlinx-coroutines-rx2/test/guide/example-reactive-basic-09.kt index 3c9ea39398..fdb9f1a46b 100644 --- a/reactive/kotlinx-coroutines-rx2/test/guide/example-reactive-basic-09.kt +++ b/reactive/kotlinx-coroutines-rx2/test/guide/example-reactive-basic-09.kt @@ -5,8 +5,9 @@ // This file was automatically generated from coroutines-guide-reactive.md by Knit tool. Do not edit. package kotlinx.coroutines.experimental.rx2.guide.basic09 -import kotlinx.coroutines.experimental.* import kotlinx.coroutines.experimental.channels.* +import kotlinx.coroutines.experimental.* +import kotlin.coroutines.experimental.* fun main(args: Array) = runBlocking { val broadcast = ConflatedBroadcastChannel() diff --git a/reactive/kotlinx-coroutines-rx2/test/guide/example-reactive-context-02.kt b/reactive/kotlinx-coroutines-rx2/test/guide/example-reactive-context-02.kt index 87f2bdd1e9..4d1df1a6cf 100644 --- a/reactive/kotlinx-coroutines-rx2/test/guide/example-reactive-context-02.kt +++ b/reactive/kotlinx-coroutines-rx2/test/guide/example-reactive-context-02.kt @@ -8,7 +8,7 @@ package kotlinx.coroutines.experimental.rx2.guide.context02 import io.reactivex.* import kotlinx.coroutines.experimental.* import kotlinx.coroutines.experimental.reactive.* -import kotlin.coroutines.experimental.* +import kotlin.coroutines.experimental.CoroutineContext fun rangeWithInterval(context: CoroutineContext, time: Long, start: Int, count: Int) = GlobalScope.publish(context) { for (x in start until start + count) { diff --git a/reactive/kotlinx-coroutines-rx2/test/guide/example-reactive-context-03.kt b/reactive/kotlinx-coroutines-rx2/test/guide/example-reactive-context-03.kt index 8e82d3684f..b92d00fdcb 100644 --- a/reactive/kotlinx-coroutines-rx2/test/guide/example-reactive-context-03.kt +++ b/reactive/kotlinx-coroutines-rx2/test/guide/example-reactive-context-03.kt @@ -6,10 +6,10 @@ package kotlinx.coroutines.experimental.rx2.guide.context03 import io.reactivex.* -import io.reactivex.schedulers.* import kotlinx.coroutines.experimental.* import kotlinx.coroutines.experimental.reactive.* -import kotlin.coroutines.experimental.* +import io.reactivex.schedulers.Schedulers +import kotlin.coroutines.experimental.CoroutineContext fun rangeWithInterval(context: CoroutineContext, time: Long, start: Int, count: Int) = GlobalScope.publish(context) { for (x in start until start + count) { diff --git a/reactive/kotlinx-coroutines-rx2/test/guide/example-reactive-context-05.kt b/reactive/kotlinx-coroutines-rx2/test/guide/example-reactive-context-05.kt index 31e11397ad..6d20c2614e 100644 --- a/reactive/kotlinx-coroutines-rx2/test/guide/example-reactive-context-05.kt +++ b/reactive/kotlinx-coroutines-rx2/test/guide/example-reactive-context-05.kt @@ -19,7 +19,7 @@ fun rangeWithIntervalRx(scheduler: Scheduler, time: Long, start: Int, count: Int BiFunction { x, _ -> x }) fun main(args: Array) = runBlocking { - val job = launch(Unconfined) { // launch new coroutine in Unconfined context (without its own thread pool) + val job = launch(Dispatchers.Unconfined) { // launch new coroutine in Unconfined context (without its own thread pool) rangeWithIntervalRx(Schedulers.computation(), 100, 1, 3) .consumeEach { println("$it on thread ${Thread.currentThread().name}") } } diff --git a/reactive/kotlinx-coroutines-rx2/test/guide/example-reactive-operators-01.kt b/reactive/kotlinx-coroutines-rx2/test/guide/example-reactive-operators-01.kt index 9177e64c85..bdceadd257 100644 --- a/reactive/kotlinx-coroutines-rx2/test/guide/example-reactive-operators-01.kt +++ b/reactive/kotlinx-coroutines-rx2/test/guide/example-reactive-operators-01.kt @@ -7,13 +7,13 @@ package kotlinx.coroutines.experimental.rx2.guide.operators01 import kotlinx.coroutines.experimental.* import kotlinx.coroutines.experimental.reactive.* -import kotlin.coroutines.experimental.* +import kotlin.coroutines.experimental.CoroutineContext fun CoroutineScope.range(context: CoroutineContext, start: Int, count: Int) = publish(context) { for (x in start until start + count) send(x) } fun main(args: Array) = runBlocking { - // Range inherits parent job from runBlocking, but overrides dispatcher with DefaultDispatcher - range(DefaultDispatcher, 1, 5).consumeEach { println(it) } + // Range inherits parent job from runBlocking, but overrides dispatcher with Dispatchers.Default + range(Dispatchers.Default, 1, 5).consumeEach { println(it) } } diff --git a/reactive/kotlinx-coroutines-rx2/test/guide/example-reactive-operators-03.kt b/reactive/kotlinx-coroutines-rx2/test/guide/example-reactive-operators-03.kt index 7db378e609..746e62642a 100644 --- a/reactive/kotlinx-coroutines-rx2/test/guide/example-reactive-operators-03.kt +++ b/reactive/kotlinx-coroutines-rx2/test/guide/example-reactive-operators-03.kt @@ -5,8 +5,8 @@ // This file was automatically generated from coroutines-guide-reactive.md by Knit tool. Do not edit. package kotlinx.coroutines.experimental.rx2.guide.operators03 -import kotlinx.coroutines.experimental.* import kotlinx.coroutines.experimental.channels.* +import kotlinx.coroutines.experimental.* import kotlinx.coroutines.experimental.reactive.* import kotlinx.coroutines.experimental.selects.* import org.reactivestreams.* diff --git a/ui/coroutines-guide-ui.md b/ui/coroutines-guide-ui.md index 781cb02c31..20d9974ca4 100644 --- a/ui/coroutines-guide-ui.md +++ b/ui/coroutines-guide-ui.md @@ -8,7 +8,7 @@ package kotlinx.coroutines.experimental.javafx.guide.$$1$$2 import kotlinx.coroutines.experimental.* import kotlinx.coroutines.experimental.channels.* -import kotlinx.coroutines.experimental.javafx.JavaFx as UI +import kotlinx.coroutines.experimental.javafx.JavaFx as Main import javafx.application.Application import javafx.event.EventHandler import javafx.geometry.* @@ -59,17 +59,17 @@ This guide assumes familiarity with basic coroutine concepts that are covered in [Guide to kotlinx.coroutines](../coroutines-guide.md) and gives specific examples on how to use coroutines in UI applications. -All UI application libraries have one thing in common. They have the single thread where all state of the UI +All UI application libraries have one thing in common. They have the single main thread where all state of the UI is confined, and all updates to the UI has to happen in this particular thread. With respect to coroutines, it means that you need an appropriate _coroutine dispatcher context_ that confines the coroutine -execution to this UI thread. +execution to this main UI thread. In particular, `kotlinx.coroutines` has three modules that provide coroutine context for different UI application libraries: -* [kotlinx-coroutines-android](kotlinx-coroutines-android) -- `UI` context for Android applications. -* [kotlinx-coroutines-javafx](kotlinx-coroutines-javafx) -- `JavaFx` context for JavaFX UI applications. -* [kotlinx-coroutines-swing](kotlinx-coroutines-swing) -- `Swing` context for Swing UI applications. +* [kotlinx-coroutines-android](kotlinx-coroutines-android) -- `Dispatchers.Main` context for Android applications. +* [kotlinx-coroutines-javafx](kotlinx-coroutines-javafx) -- `Dispatchers.JavaFx` context for JavaFX UI applications. +* [kotlinx-coroutines-swing](kotlinx-coroutines-swing) -- `Dispatchers.Swing` context for Swing UI applications. This guide covers all UI libraries simultaneously, because each of these modules consists of just one object definition that is a couple of pages long. You can use any of them as an example to write the corresponding @@ -182,19 +182,23 @@ This section shows basic usage of coroutines in UI applications. ### Launch UI coroutine -The `kotlinx-coroutines-javafx` module contains [JavaFx] context that dispatches coroutine execution to -the JavaFx application thread. We import it as `UI` to make all the presented examples +The `kotlinx-coroutines-javafx` module contains [Dispatchers.JavaFx] dispatcher that dispatches coroutine execution to +the JavaFx application thread. We import it as `Main` to make all the presented examples easily portable to Android: +```kotlin +import kotlinx.coroutines.experimental.javafx.JavaFx as Main +``` + -Coroutines confined to the UI thread can freely update anything in UI and suspend without blocking the UI thread. +Coroutines confined to the main UI thread can freely update anything in UI and suspend without blocking the main thread. For example, we can perform animations by coding them in imperative style. The following code updates the text with a 10 to 1 countdown twice a second, using [launch] coroutine builder: ```kotlin fun setup(hello: Text, fab: Circle) { - GlobalScope.launch(UI) { // launch coroutine in UI context + GlobalScope.launch(Dispatchers.Main) { // launch coroutine in the main thread for (i in 10 downTo 1) { // countdown from 10 to 1 hello.text = "Countdown $i ..." // update text delay(500) // wait half a second @@ -206,7 +210,7 @@ fun setup(hello: Text, fab: Circle) { > You can get full code [here](kotlinx-coroutines-javafx/test/guide/example-ui-basic-02.kt) -So, what happens here? Because we are launching coroutine in UI context, we can freely update UI from +So, what happens here? Because we are launching coroutine in the main UI context, we can freely update UI from inside this coroutine and invoke _suspending functions_ like [delay] at the same time. UI is not frozen while `delay` waits, because it does not block the UI thread -- it just suspends the coroutine. @@ -220,7 +224,7 @@ coroutine when we want to stop it. Let us cancel the coroutine when pinkish circ ```kotlin fun setup(hello: Text, fab: Circle) { - val job = GlobalScope.launch(UI) { // launch coroutine in UI context + val job = GlobalScope.launch(Dispatchers.Main) { // launch coroutine in the main thread for (i in 10 downTo 1) { // countdown from 10 to 1 hello.text = "Countdown $i ..." // update text delay(500) // wait half a second @@ -276,7 +280,7 @@ passes the corresponding mouse event into the supplied action (just in case we n ```kotlin fun Node.onClick(action: suspend (MouseEvent) -> Unit) { onMouseClicked = EventHandler { event -> - GlobalScope.launch(UI) { + GlobalScope.launch(Dispatchers.Main) { action(event) } } @@ -295,7 +299,7 @@ update the text. Try it. It does not look very good. We'll fix it later. ```kotlin fun View.onClick(action: suspend () -> Unit) { setOnClickListener { - GlobalScope.launch(UI) { + GlobalScope.launch(Dispatchers.Main) { action() } } @@ -315,7 +319,7 @@ not be performed concurrently. Let us change `onClick` extension implementation: ```kotlin fun Node.onClick(action: suspend (MouseEvent) -> Unit) { // launch one actor to handle all events on this node - val eventActor = GlobalScope.actor(UI) { + val eventActor = GlobalScope.actor(Dispatchers.Main) { for (event in channel) action(event) // pass event to action } // install a listener to offer events to this actor @@ -342,7 +346,7 @@ the `receive` is active. ```kotlin fun View.onClick(action: suspend (View) -> Unit) { // launch one actor - val eventActor = GlobalScope.actor(UI) { + val eventActor = GlobalScope.actor(Dispatchers.Main) { for (event in channel) action(event) } // install a listener to activate this actor @@ -368,7 +372,7 @@ change is only to the line that creates an actor: ```kotlin fun Node.onClick(action: suspend (MouseEvent) -> Unit) { // launch one actor to handle all events on this node - val eventActor = GlobalScope.actor(UI, capacity = Channel.CONFLATED) { // <--- Changed here + val eventActor = GlobalScope.actor(Dispatchers.Main, capacity = Channel.CONFLATED) { // <--- Changed here for (event in channel) action(event) // pass event to action } // install a listener to offer events to this actor @@ -402,13 +406,13 @@ This section explains how to use UI coroutines with thread-blocking operations. It would have been great if all APIs out there were written as suspending functions that never blocks an execution thread. However, it is quite often not the case. Sometimes you need to do a CPU-consuming computation or just need to invoke some 3rd party APIs for network access, for example, that blocks the invoker thread. -You cannot do that from the UI thread nor from the UI-confined coroutine directly, because that would -block the UI thread and cause the freeze up of the UI. +You cannot do that from the main UI thread nor from the UI-confined coroutine directly, because that would +block the main UI thread and cause the freeze up of the UI. The following example illustrates the problem. We are going to use `onClick` extension with UI-confined -event-conflating actor from the last section to process the last click in the UI thread. +event-conflating actor from the last section to process the last click in the main UI thread. For this example, we are going to perform naive computation of [Fibonacci numbers](https://en.wikipedia.org/wiki/Fibonacci_number): @@ -429,13 +433,13 @@ fun fib(x: Int): Int = We'll be computing larger and larger Fibonacci number each time the circle is clicked. To make the UI freeze more obvious, there is also a fast counting animation that is always running -and is constantly updating the text in the UI context: +and is constantly updating the text in the main UI dispatcher: ```kotlin fun setup(hello: Text, fab: Circle) { var result = "none" // the last result // counting animation - GlobalScope.launch(UI) { + GlobalScope.launch(Dispatchers.Main) { var counter = 0 while (true) { hello.text = "${++counter}: $result" @@ -455,7 +459,7 @@ fun setup(hello: Text, fab: Circle) { You can just copy the `fib` function and the body of the `setup` function to your Android project. Try clicking on the circle in this example. After around 30-40th click our naive computation is going to become -quite slow and you would immediately see how the UI thread freezes, because the animation stops running +quite slow and you would immediately see how the main UI thread freezes, because the animation stops running during UI freeze. ### Structured concurrency, lifecycle and coroutine parent-child hierarchy @@ -479,7 +483,7 @@ instance of a `Job` to an instance of an `Activity`: abstract class ScopedAppActivity: AppCompatActivity(), CoroutineScope { protected lateinit var job: Job override val coroutineContext: CoroutineContext - get() = job + UI + get() = job + Dispatchers.Main override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) @@ -503,10 +507,10 @@ class MainActivity : ScopedAppActivity() { } suspend fun showIOData() { - val deferred = async(IO) { + val deferred = async(Dispatchers.IO) { // impl } - withContext(UI) { + withContext(Dispatchers.Main) { val data = deferred.await() // Show data in UI } @@ -549,10 +553,11 @@ when the parent job is cancelled. An example of that is shown in the ### Blocking operations -The fix for the blocking operations on the UI thread is quite straightforward with coroutines. We'll +The fix for the blocking operations on the main UI thread is quite straightforward with coroutines. We'll convert our "blocking" `fib` function to a non-blocking suspending function that runs the computation in -the background thread by using [withContext] function to change its execution context to [CommonPool] of background -threads. Notice, that `fib` function is now marked with `suspend` modifier. It does not block the coroutine that +the background thread by using [withContext] function to change its execution context to [Dispathers.Default] that is +backed by the background pool of threads. +Notice, that `fib` function is now marked with `suspend` modifier. It does not block the coroutine that it is invoked from anymore, but suspends its execution when the computation in the background thread is working: ```kotlin -suspend fun fib(x: Int): Int = withContext(CommonPool) { +suspend fun fib(x: Int): Int = withContext(Dispatchers.Default) { if (x <= 1) x else fib(x - 1) + fib(x - 2) } ``` @@ -596,7 +601,7 @@ Still, this particular `fib` implementation can be made to run as fast as before the original `fib` function to `fibBlocking` and defining `fib` with `withContext` wrapper on top of `fibBlocking`: ```kotlin -suspend fun fib(x: Int): Int = withContext(CommonPool) { +suspend fun fib(x: Int): Int = withContext(Dispatchers.Default) { fibBlocking(x) } @@ -606,7 +611,8 @@ fun fibBlocking(x: Int): Int = > You can get full code [here](kotlinx-coroutines-javafx/test/guide/example-ui-blocking-03.kt). -You can now enjoy full-speed naive Fibonacci computation without blocking the UI thread. All we need is `withContext(CommonPool)`. +You can now enjoy full-speed naive Fibonacci computation without blocking the main UI thread. +All we need is `withContext(Dispatchers.Default)`. Note, that because the `fib` function is invoked from the single actor in our code, there is at most one concurrent computation of it at any given time, so this code has a natural limit on the resource utilization. @@ -627,7 +633,7 @@ from the UI thread: fun setup(hello: Text, fab: Circle) { fab.onMouseClicked = EventHandler { println("Before launch") - GlobalScope.launch(UI) { + GlobalScope.launch(Dispatchers.Main) { println("Inside coroutine") delay(100) println("After delay") @@ -648,7 +654,7 @@ Inside coroutine After delay ``` -As you can see, execution immediately continues after [launch], while the coroutine gets posted onto UI thread +As you can see, execution immediately continues after [launch], while the coroutine gets posted onto the main UI thread for execution later. All UI dispatchers in `kotlinx.coroutines` are implemented this way. Why so? Basically, the choice here is between "JS-style" asynchronous approach (async actions @@ -669,7 +675,7 @@ coroutine immediately until its first suspension point as the following example fun setup(hello: Text, fab: Circle) { fab.onMouseClicked = EventHandler { println("Before launch") - GlobalScope.launch(UI, CoroutineStart.UNDISPATCHED) { // <--- Notice this change + GlobalScope.launch(Dispatchers.Main, CoroutineStart.UNDISPATCHED) { // <--- Notice this change println("Inside coroutine") delay(100) // <--- And this is where coroutine suspends println("After delay") @@ -699,7 +705,6 @@ After delay [CoroutineScope]: https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines.experimental/-coroutine-scope/index.html [currentScope]: https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines.experimental/current-scope.html [withContext]: https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines.experimental/with-context.html -[CommonPool]: https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines.experimental/-common-pool/index.html [CoroutineStart]: https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines.experimental/-coroutine-start/index.html [async]: https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines.experimental/async.html [CoroutineStart.UNDISPATCHED]: https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines.experimental/-coroutine-start/-u-n-d-i-s-p-a-t-c-h-e-d.html @@ -714,7 +719,6 @@ After delay [LinkedListChannel]: https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines.experimental.channels/-linked-list-channel/index.html -[JavaFx]: https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-javafx/kotlinx.coroutines.experimental.javafx/-java-fx/index.html diff --git a/ui/kotlinx-coroutines-android/src/HandlerContext.kt b/ui/kotlinx-coroutines-android/src/HandlerContext.kt deleted file mode 100644 index 36b55748a9..0000000000 --- a/ui/kotlinx-coroutines-android/src/HandlerContext.kt +++ /dev/null @@ -1,115 +0,0 @@ -/* - * Copyright 2016-2018 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license. - */ - -package kotlinx.coroutines.experimental.android - -import android.os.* -import android.view.* -import kotlinx.coroutines.experimental.* -import java.util.concurrent.TimeUnit -import kotlin.coroutines.experimental.CoroutineContext - -/** - * Dispatches execution onto Android main UI thread and provides native [delay][Delay.delay] support. - */ -val UI = HandlerContext(Handler(Looper.getMainLooper()), "UI") - -/** - * Represents an arbitrary [Handler] as a implementation of [CoroutineDispatcher]. - */ -fun Handler.asCoroutineDispatcher() = HandlerContext(this) - -private const val MAX_DELAY = Long.MAX_VALUE / 2 // cannot delay for too long on Android - -/** - * Implements [CoroutineDispatcher] on top of an arbitrary Android [Handler]. - */ -public class HandlerContext private constructor( - private val handler: Handler, - private val name: String?, - private val invokeImmediately: Boolean -) : CoroutineDispatcher(), Delay { - /** - * Creates [CoroutineDispatcher] for the given Android [handler]. - * - * @param handler a handler. - * @param name an optional name for debugging. - */ - public constructor( - handler: Handler, - name: String? = null - ) : this(handler, name, false) - - @Volatile - private var _immediate: HandlerContext? = if (invokeImmediately) this else null - - /** - * Returns dispatcher that executes coroutines immediately when it is already in the right handler context - * (current looper is the same as [handler] looper). See [isDispatchNeeded] documentation on - * why this should not be done by default. - */ - public val immediate: HandlerContext = _immediate ?: - HandlerContext(handler, name, true).also { _immediate = it } - - @Volatile - private var _choreographer: Choreographer? = null - - override fun isDispatchNeeded(context: CoroutineContext): Boolean { - return !invokeImmediately || Looper.myLooper() != handler.looper - } - - override fun dispatch(context: CoroutineContext, block: Runnable) { - handler.post(block) - } - - override fun scheduleResumeAfterDelay(time: Long, unit: TimeUnit, continuation: CancellableContinuation) { - handler.postDelayed({ - with(continuation) { resumeUndispatched(Unit) } - }, unit.toMillis(time).coerceAtMost(MAX_DELAY)) - } - - override fun invokeOnTimeout(time: Long, unit: TimeUnit, block: Runnable): DisposableHandle { - handler.postDelayed(block, unit.toMillis(time).coerceAtMost(MAX_DELAY)) - return object : DisposableHandle { - override fun dispose() { - handler.removeCallbacks(block) - } - } - } - - /** - * Awaits the next animation frame and returns frame time in nanoseconds. - */ - public suspend fun awaitFrame(): Long { - // fast path when choreographer is already known - val choreographer = _choreographer - if (choreographer != null) { - return suspendCancellableCoroutine { cont -> - postFrameCallback(choreographer, cont) - } - } - // post into looper thread thread to figure it out - return suspendCancellableCoroutine { cont -> - handler.post { - updateChoreographerAndPostFrameCallback(cont) - } - } - } - - private fun updateChoreographerAndPostFrameCallback(cont: CancellableContinuation) { - val choreographer = _choreographer ?: - Choreographer.getInstance()!!.also { _choreographer = it } - postFrameCallback(choreographer, cont) - } - - private fun postFrameCallback(choreographer: Choreographer, cont: CancellableContinuation) { - choreographer.postFrameCallback { nanos -> - with(cont) { resumeUndispatched(nanos) } - } - } - - override fun toString() = name ?: handler.toString() - override fun equals(other: Any?): Boolean = other is HandlerContext && other.handler === handler - override fun hashCode(): Int = System.identityHashCode(handler) -} diff --git a/ui/kotlinx-coroutines-android/src/HandlerDispatcher.kt b/ui/kotlinx-coroutines-android/src/HandlerDispatcher.kt new file mode 100644 index 0000000000..f9499a1f7b --- /dev/null +++ b/ui/kotlinx-coroutines-android/src/HandlerDispatcher.kt @@ -0,0 +1,164 @@ +/* + * Copyright 2016-2018 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license. + */ + +package kotlinx.coroutines.experimental.android + +import android.os.* +import android.view.* +import kotlinx.coroutines.experimental.* +import java.util.concurrent.* +import kotlin.coroutines.experimental.* + +/** + * Dispatches execution onto Android main UI thread and provides native [delay][Delay.delay] support. + */ +public val Dispatchers.Main: HandlerDispatcher + get() = mainDispatcher + +/** + * Dispatches execution onto Android [Handler]. + * + * This class provides type-safety and a point for future extensions. + */ +public sealed class HandlerDispatcher : CoroutineDispatcher(), Delay { + /** + * Returns dispatcher that executes coroutines immediately when it is already in the right handler context + * (current looper is the same as this handler's looper). See [isDispatchNeeded] documentation on + * why this should not be done by default. + */ + public abstract val immediate: HandlerDispatcher +} + +/** + * Represents an arbitrary [Handler] as a implementation of [CoroutineDispatcher]. + */ +public fun Handler.asCoroutineDispatcher(): HandlerDispatcher = + HandlerContext(this) + +/** + * Dispatches execution onto Android main UI thread and provides native [delay][Delay.delay] support. + * @suppress **Deprecated**: Use [Dispatchers.Main]. + */ +@Deprecated( + message = "Use Dispatchers.Main", + replaceWith = ReplaceWith("Dispatchers.Main", + imports = ["kotlinx.coroutines.experimental.Dispatchers", "kotlinx.coroutines.experimental.android.Main"]) +) +val UI: HandlerContext + get() = mainDispatcher + +@Deprecated(level = DeprecationLevel.HIDDEN, message = "Binary compatibility") +@JvmName("asCoroutineDispatcher") +public fun Handler.asCoroutineDispatcher0(): HandlerContext = + HandlerContext(this) + +private const val MAX_DELAY = Long.MAX_VALUE / 2 // cannot delay for too long on Android + +private val mainHandler = Handler(Looper.getMainLooper()) +private val mainDispatcher = HandlerContext(mainHandler, "Main") + +/** + * Implements [CoroutineDispatcher] on top of an arbitrary Android [Handler]. + * @suppress **Deprecated**: Use [HandlerDispatcher]. + */ +@Deprecated( + message = "Use HandlerDispatcher", + replaceWith = ReplaceWith("HandlerDispatcher", + imports = ["kotlinx.coroutines.experimental.android.HandlerDispatcher"]) +) +public class HandlerContext private constructor( + private val handler: Handler, + private val name: String?, + private val invokeImmediately: Boolean +) : HandlerDispatcher(), Delay { + /** + * Creates [CoroutineDispatcher] for the given Android [handler]. + * + * @param handler a handler. + * @param name an optional name for debugging. + */ + public constructor( + handler: Handler, + name: String? = null + ) : this(handler, name, false) + + @Volatile + private var _immediate: HandlerContext? = if (invokeImmediately) this else null + + override val immediate: HandlerContext = _immediate ?: + HandlerContext(handler, name, true).also { _immediate = it } + + override fun isDispatchNeeded(context: CoroutineContext): Boolean { + return !invokeImmediately || Looper.myLooper() != handler.looper + } + + override fun dispatch(context: CoroutineContext, block: Runnable) { + handler.post(block) + } + + override fun scheduleResumeAfterDelay(time: Long, unit: TimeUnit, continuation: CancellableContinuation) { + handler.postDelayed({ + with(continuation) { resumeUndispatched(Unit) } + }, unit.toMillis(time).coerceAtMost(MAX_DELAY)) + } + + override fun invokeOnTimeout(time: Long, unit: TimeUnit, block: Runnable): DisposableHandle { + handler.postDelayed(block, unit.toMillis(time).coerceAtMost(MAX_DELAY)) + return object : DisposableHandle { + override fun dispose() { + handler.removeCallbacks(block) + } + } + } + + /** + * Awaits the next animation frame and returns frame time in nanoseconds. + * @suppress **Deprecated**: Use top-level [awaitFrame]. + */ + @Deprecated( + message = "Use top-level awaitFrame", + replaceWith = ReplaceWith("kotlinx.coroutines.experimental.android.awaitFrame()") + ) + public suspend fun awaitFrame(): Long = + kotlinx.coroutines.experimental.android.awaitFrame() + + override fun toString() = name ?: handler.toString() + + override fun equals(other: Any?): Boolean = other is HandlerContext && other.handler === handler + override fun hashCode(): Int = System.identityHashCode(handler) +} + +@Volatile +private var choreographer: Choreographer? = null + +/** + * Awaits the next animation frame and returns frame time in nanoseconds. + */ +public suspend fun awaitFrame(): Long { + // fast path when choreographer is already known + val choreographer = choreographer + if (choreographer != null) { + return suspendCancellableCoroutine { cont -> + postFrameCallback(choreographer, cont) + } + } + // post into looper thread thread to figure it out + return suspendCancellableCoroutine { cont -> + mainHandler.post { + updateChoreographerAndPostFrameCallback(cont) + } + } +} + +private fun updateChoreographerAndPostFrameCallback(cont: CancellableContinuation) { + val choreographer = choreographer ?: + Choreographer.getInstance()!!.also { choreographer = it } + postFrameCallback(choreographer, cont) +} + +private fun postFrameCallback(choreographer: Choreographer, cont: CancellableContinuation) { + choreographer.postFrameCallback { nanos -> + with(cont) { mainDispatcher.resumeUndispatched(nanos) } + } +} diff --git a/ui/kotlinx-coroutines-javafx/src/JavaFx.kt b/ui/kotlinx-coroutines-javafx/src/JavaFxDispatcher.kt similarity index 53% rename from ui/kotlinx-coroutines-javafx/src/JavaFx.kt rename to ui/kotlinx-coroutines-javafx/src/JavaFxDispatcher.kt index 2aa59810c0..cbeba407d5 100644 --- a/ui/kotlinx-coroutines-javafx/src/JavaFx.kt +++ b/ui/kotlinx-coroutines-javafx/src/JavaFxDispatcher.kt @@ -10,33 +10,54 @@ import javafx.event.* import javafx.util.* import kotlinx.coroutines.experimental.* import kotlinx.coroutines.experimental.javafx.JavaFx.delay -import java.util.concurrent.CopyOnWriteArrayList -import java.util.concurrent.TimeUnit -import kotlin.coroutines.experimental.CoroutineContext +import java.util.concurrent.* +import kotlin.coroutines.experimental.* /** * Dispatches execution onto JavaFx application thread and provides native [delay] support. */ -object JavaFx : CoroutineDispatcher(), Delay { +public val Dispatchers.JavaFx: JavaFxDispatcher + get() = kotlinx.coroutines.experimental.javafx.JavaFx + +/** + * Dispatcher for JavaFx application thread with support for [awaitPulse]. + * + * This class provides type-safety and a point for future extensions. + */ +public sealed class JavaFxDispatcher : CoroutineDispatcher(), Delay { +} + +/** + * Dispatches execution onto JavaFx application thread and provides native [delay] support. + * @suppress **Deprecated**: Use [Dispatchers.JavaFx]. + */ +@Deprecated( + message = "Use Dispatchers.Main", + replaceWith = ReplaceWith("Dispatchers.JavaFx", + imports = ["kotlinx.coroutines.experimental.Dispatchers", "kotlinx.coroutines.experimental.javafx.JavaFx"]) +) +// todo: it will become an internal implementation object +object JavaFx : JavaFxDispatcher(), Delay { init { // :kludge: to make sure Toolkit is initialized if we use JavaFx dispatcher outside of JavaFx app initPlatform() } - private val pulseTimer by lazy { - PulseTimer().apply { start() } - } - override fun dispatch(context: CoroutineContext, block: Runnable) = Platform.runLater(block) /** * Suspends coroutine until next JavaFx pulse and returns time of the pulse on resumption. * If the [Job] of the current coroutine is completed while this suspending function is waiting, this function * immediately resumes with [CancellationException] . + * + * @suppress **Deprecated**: Use top-level [awaitPulse]. */ - suspend fun awaitPulse(): Long = suspendCancellableCoroutine { cont -> - pulseTimer.onNext(cont) - } + @Deprecated( + message = "Use top-level awaitFrame", + replaceWith = ReplaceWith("kotlinx.coroutines.experimental.javafx.awaitPulse()") + ) + suspend fun awaitPulse(): Long = + kotlinx.coroutines.experimental.javafx.awaitPulse() override fun scheduleResumeAfterDelay(time: Long, unit: TimeUnit, continuation: CancellableContinuation) { val timeline = schedule(time, unit, EventHandler { @@ -59,22 +80,35 @@ object JavaFx : CoroutineDispatcher(), Delay { private fun schedule(time: Long, unit: TimeUnit, handler: EventHandler): Timeline = Timeline(KeyFrame(Duration.millis(unit.toMillis(time).toDouble()), handler)).apply { play() } - private class PulseTimer : AnimationTimer() { - val next = CopyOnWriteArrayList>() + override fun toString() = "JavaFx" +} - override fun handle(now: Long) { - val cur = next.toTypedArray() - next.clear() - for (cont in cur) - with (cont) { resumeUndispatched(now) } - } +private val pulseTimer by lazy { + PulseTimer().apply { start() } +} - fun onNext(cont: CancellableContinuation) { - next += cont - } +/** + * Suspends coroutine until next JavaFx pulse and returns time of the pulse on resumption. + * If the [Job] of the current coroutine is completed while this suspending function is waiting, this function + * immediately resumes with [CancellationException] . + */ +public suspend fun awaitPulse(): Long = suspendCancellableCoroutine { cont -> + pulseTimer.onNext(cont) +} + +private class PulseTimer : AnimationTimer() { + val next = CopyOnWriteArrayList>() + + override fun handle(now: Long) { + val cur = next.toTypedArray() + next.clear() + for (cont in cur) + with (cont) { JavaFx.resumeUndispatched(now) } } - override fun toString() = "JavaFx" + fun onNext(cont: CancellableContinuation) { + next += cont + } } internal fun initPlatform() { diff --git a/ui/kotlinx-coroutines-javafx/test/JavaFxTest.kt b/ui/kotlinx-coroutines-javafx/test/JavaFxTest.kt index 7079fca4ef..4bade22834 100644 --- a/ui/kotlinx-coroutines-javafx/test/JavaFxTest.kt +++ b/ui/kotlinx-coroutines-javafx/test/JavaFxTest.kt @@ -25,7 +25,7 @@ class JavaFxTest : TestBase() { runBlocking { expect(1) - val job = launch(JavaFx) { + val job = launch(Dispatchers.JavaFx) { check(Platform.isFxApplicationThread()) expect(2) delay(100) diff --git a/ui/kotlinx-coroutines-javafx/test/examples/FxExampleApp.kt b/ui/kotlinx-coroutines-javafx/test/examples/FxExampleApp.kt index 6d76170160..77eb98e3b1 100644 --- a/ui/kotlinx-coroutines-javafx/test/examples/FxExampleApp.kt +++ b/ui/kotlinx-coroutines-javafx/test/examples/FxExampleApp.kt @@ -52,7 +52,7 @@ class FxTestApp : Application(), CoroutineScope { var animationIndex = 0 var job = Job() override val coroutineContext: CoroutineContext - get() = JavaFx + job + get() = Dispatchers.JavaFx + job private fun animation(node: Node, block: suspend CoroutineScope.() -> Unit) { root.children += node @@ -71,7 +71,7 @@ class FxTestApp : Application(), CoroutineScope { var vy = speed var counter = 0 while (true) { - JavaFx.awaitPulse() + awaitPulse() node.x += vx node.y += vy val xRange = 0.0 .. scene.width - node.width @@ -108,7 +108,7 @@ class FxTestApp : Application(), CoroutineScope { var sx = random.nextDouble() * maxSpeed var sy = random.nextDouble() * maxSpeed while (true) { - JavaFx.awaitPulse() + awaitPulse() val dx = root.width / 2 - node.translateX val dy = root.height / 2 - node.translateY val dn = Math.sqrt(dx * dx + dy * dy) diff --git a/ui/kotlinx-coroutines-javafx/test/guide/example-ui-actor-01.kt b/ui/kotlinx-coroutines-javafx/test/guide/example-ui-actor-01.kt index a70e104fc3..53fdb56f0d 100644 --- a/ui/kotlinx-coroutines-javafx/test/guide/example-ui-actor-01.kt +++ b/ui/kotlinx-coroutines-javafx/test/guide/example-ui-actor-01.kt @@ -7,7 +7,7 @@ package kotlinx.coroutines.experimental.javafx.guide.actor01 import kotlinx.coroutines.experimental.* import kotlinx.coroutines.experimental.channels.* -import kotlinx.coroutines.experimental.javafx.JavaFx as UI +import kotlinx.coroutines.experimental.javafx.JavaFx as Main import javafx.application.Application import javafx.event.EventHandler import javafx.geometry.* @@ -62,7 +62,7 @@ fun setup(hello: Text, fab: Circle) { fun Node.onClick(action: suspend (MouseEvent) -> Unit) { onMouseClicked = EventHandler { event -> - GlobalScope.launch(UI) { + GlobalScope.launch(Dispatchers.Main) { action(event) } } diff --git a/ui/kotlinx-coroutines-javafx/test/guide/example-ui-actor-02.kt b/ui/kotlinx-coroutines-javafx/test/guide/example-ui-actor-02.kt index bb1c4a217c..3211f8591b 100644 --- a/ui/kotlinx-coroutines-javafx/test/guide/example-ui-actor-02.kt +++ b/ui/kotlinx-coroutines-javafx/test/guide/example-ui-actor-02.kt @@ -7,7 +7,7 @@ package kotlinx.coroutines.experimental.javafx.guide.actor02 import kotlinx.coroutines.experimental.* import kotlinx.coroutines.experimental.channels.* -import kotlinx.coroutines.experimental.javafx.JavaFx as UI +import kotlinx.coroutines.experimental.javafx.JavaFx as Main import javafx.application.Application import javafx.event.EventHandler import javafx.geometry.* @@ -62,7 +62,7 @@ fun setup(hello: Text, fab: Circle) { fun Node.onClick(action: suspend (MouseEvent) -> Unit) { // launch one actor to handle all events on this node - val eventActor = GlobalScope.actor(UI) { + val eventActor = GlobalScope.actor(Dispatchers.Main) { for (event in channel) action(event) // pass event to action } // install a listener to offer events to this actor diff --git a/ui/kotlinx-coroutines-javafx/test/guide/example-ui-actor-03.kt b/ui/kotlinx-coroutines-javafx/test/guide/example-ui-actor-03.kt index 5b22c2a0fa..3530e6e1ff 100644 --- a/ui/kotlinx-coroutines-javafx/test/guide/example-ui-actor-03.kt +++ b/ui/kotlinx-coroutines-javafx/test/guide/example-ui-actor-03.kt @@ -7,7 +7,7 @@ package kotlinx.coroutines.experimental.javafx.guide.actor03 import kotlinx.coroutines.experimental.* import kotlinx.coroutines.experimental.channels.* -import kotlinx.coroutines.experimental.javafx.JavaFx as UI +import kotlinx.coroutines.experimental.javafx.JavaFx as Main import javafx.application.Application import javafx.event.EventHandler import javafx.geometry.* @@ -62,7 +62,7 @@ fun setup(hello: Text, fab: Circle) { fun Node.onClick(action: suspend (MouseEvent) -> Unit) { // launch one actor to handle all events on this node - val eventActor = GlobalScope.actor(UI, capacity = Channel.CONFLATED) { // <--- Changed here + val eventActor = GlobalScope.actor(Dispatchers.Main, capacity = Channel.CONFLATED) { // <--- Changed here for (event in channel) action(event) // pass event to action } // install a listener to offer events to this actor diff --git a/ui/kotlinx-coroutines-javafx/test/guide/example-ui-advanced-01.kt b/ui/kotlinx-coroutines-javafx/test/guide/example-ui-advanced-01.kt index 33f7099151..5cc9f7e000 100644 --- a/ui/kotlinx-coroutines-javafx/test/guide/example-ui-advanced-01.kt +++ b/ui/kotlinx-coroutines-javafx/test/guide/example-ui-advanced-01.kt @@ -7,7 +7,7 @@ package kotlinx.coroutines.experimental.javafx.guide.advanced01 import kotlinx.coroutines.experimental.* import kotlinx.coroutines.experimental.channels.* -import kotlinx.coroutines.experimental.javafx.JavaFx as UI +import kotlinx.coroutines.experimental.javafx.JavaFx as Main import javafx.application.Application import javafx.event.EventHandler import javafx.geometry.* @@ -53,7 +53,7 @@ class ExampleApp : Application() { fun setup(hello: Text, fab: Circle) { fab.onMouseClicked = EventHandler { println("Before launch") - GlobalScope.launch(UI) { + GlobalScope.launch(Dispatchers.Main) { println("Inside coroutine") delay(100) println("After delay") diff --git a/ui/kotlinx-coroutines-javafx/test/guide/example-ui-advanced-02.kt b/ui/kotlinx-coroutines-javafx/test/guide/example-ui-advanced-02.kt index 2f3a2f5ff5..8d2017b79f 100644 --- a/ui/kotlinx-coroutines-javafx/test/guide/example-ui-advanced-02.kt +++ b/ui/kotlinx-coroutines-javafx/test/guide/example-ui-advanced-02.kt @@ -7,7 +7,7 @@ package kotlinx.coroutines.experimental.javafx.guide.advanced02 import kotlinx.coroutines.experimental.* import kotlinx.coroutines.experimental.channels.* -import kotlinx.coroutines.experimental.javafx.JavaFx as UI +import kotlinx.coroutines.experimental.javafx.JavaFx as Main import javafx.application.Application import javafx.event.EventHandler import javafx.geometry.* @@ -53,7 +53,7 @@ class ExampleApp : Application() { fun setup(hello: Text, fab: Circle) { fab.onMouseClicked = EventHandler { println("Before launch") - GlobalScope.launch(UI, CoroutineStart.UNDISPATCHED) { // <--- Notice this change + GlobalScope.launch(Dispatchers.Main, CoroutineStart.UNDISPATCHED) { // <--- Notice this change println("Inside coroutine") delay(100) // <--- And this is where coroutine suspends println("After delay") diff --git a/ui/kotlinx-coroutines-javafx/test/guide/example-ui-basic-01.kt b/ui/kotlinx-coroutines-javafx/test/guide/example-ui-basic-01.kt index 707e37a0ad..f8a42ec330 100644 --- a/ui/kotlinx-coroutines-javafx/test/guide/example-ui-basic-01.kt +++ b/ui/kotlinx-coroutines-javafx/test/guide/example-ui-basic-01.kt @@ -7,7 +7,7 @@ package kotlinx.coroutines.experimental.javafx.guide.basic01 import kotlinx.coroutines.experimental.* import kotlinx.coroutines.experimental.channels.* -import kotlinx.coroutines.experimental.javafx.JavaFx as UI +import kotlinx.coroutines.experimental.javafx.JavaFx as Main import javafx.application.Application import javafx.event.EventHandler import javafx.geometry.* diff --git a/ui/kotlinx-coroutines-javafx/test/guide/example-ui-basic-02.kt b/ui/kotlinx-coroutines-javafx/test/guide/example-ui-basic-02.kt index 7ab01ad16a..3bf2160947 100644 --- a/ui/kotlinx-coroutines-javafx/test/guide/example-ui-basic-02.kt +++ b/ui/kotlinx-coroutines-javafx/test/guide/example-ui-basic-02.kt @@ -7,7 +7,7 @@ package kotlinx.coroutines.experimental.javafx.guide.basic02 import kotlinx.coroutines.experimental.* import kotlinx.coroutines.experimental.channels.* -import kotlinx.coroutines.experimental.javafx.JavaFx as UI +import kotlinx.coroutines.experimental.javafx.JavaFx as Main import javafx.application.Application import javafx.event.EventHandler import javafx.geometry.* @@ -51,7 +51,7 @@ class ExampleApp : Application() { } fun setup(hello: Text, fab: Circle) { - GlobalScope.launch(UI) { // launch coroutine in UI context + GlobalScope.launch(Dispatchers.Main) { // launch coroutine in the main thread for (i in 10 downTo 1) { // countdown from 10 to 1 hello.text = "Countdown $i ..." // update text delay(500) // wait half a second diff --git a/ui/kotlinx-coroutines-javafx/test/guide/example-ui-basic-03.kt b/ui/kotlinx-coroutines-javafx/test/guide/example-ui-basic-03.kt index 85b6a38cc7..dd8c9c4f60 100644 --- a/ui/kotlinx-coroutines-javafx/test/guide/example-ui-basic-03.kt +++ b/ui/kotlinx-coroutines-javafx/test/guide/example-ui-basic-03.kt @@ -7,7 +7,7 @@ package kotlinx.coroutines.experimental.javafx.guide.basic03 import kotlinx.coroutines.experimental.* import kotlinx.coroutines.experimental.channels.* -import kotlinx.coroutines.experimental.javafx.JavaFx as UI +import kotlinx.coroutines.experimental.javafx.JavaFx as Main import javafx.application.Application import javafx.event.EventHandler import javafx.geometry.* @@ -51,7 +51,7 @@ class ExampleApp : Application() { } fun setup(hello: Text, fab: Circle) { - val job = GlobalScope.launch(UI) { // launch coroutine in UI context + val job = GlobalScope.launch(Dispatchers.Main) { // launch coroutine in the main thread for (i in 10 downTo 1) { // countdown from 10 to 1 hello.text = "Countdown $i ..." // update text delay(500) // wait half a second diff --git a/ui/kotlinx-coroutines-javafx/test/guide/example-ui-blocking-01.kt b/ui/kotlinx-coroutines-javafx/test/guide/example-ui-blocking-01.kt index e5ecd8fecf..6093fd4f04 100644 --- a/ui/kotlinx-coroutines-javafx/test/guide/example-ui-blocking-01.kt +++ b/ui/kotlinx-coroutines-javafx/test/guide/example-ui-blocking-01.kt @@ -7,7 +7,7 @@ package kotlinx.coroutines.experimental.javafx.guide.blocking01 import kotlinx.coroutines.experimental.* import kotlinx.coroutines.experimental.channels.* -import kotlinx.coroutines.experimental.javafx.JavaFx as UI +import kotlinx.coroutines.experimental.javafx.JavaFx as Main import javafx.application.Application import javafx.event.EventHandler import javafx.geometry.* @@ -51,7 +51,7 @@ class ExampleApp : Application() { } fun Node.onClick(action: suspend (MouseEvent) -> Unit) { - val eventActor = actor(UI, capacity = Channel.CONFLATED) { + val eventActor = actor(Dispatchers.Main, capacity = Channel.CONFLATED) { for (event in channel) action(event) // pass event to action } onMouseClicked = EventHandler { event -> @@ -65,7 +65,7 @@ fun fib(x: Int): Int = fun setup(hello: Text, fab: Circle) { var result = "none" // the last result // counting animation - GlobalScope.launch(UI) { + GlobalScope.launch(Dispatchers.Main) { var counter = 0 while (true) { hello.text = "${++counter}: $result" diff --git a/ui/kotlinx-coroutines-javafx/test/guide/example-ui-blocking-02.kt b/ui/kotlinx-coroutines-javafx/test/guide/example-ui-blocking-02.kt index 02cc86f930..55eec70468 100644 --- a/ui/kotlinx-coroutines-javafx/test/guide/example-ui-blocking-02.kt +++ b/ui/kotlinx-coroutines-javafx/test/guide/example-ui-blocking-02.kt @@ -7,7 +7,7 @@ package kotlinx.coroutines.experimental.javafx.guide.blocking02 import kotlinx.coroutines.experimental.* import kotlinx.coroutines.experimental.channels.* -import kotlinx.coroutines.experimental.javafx.JavaFx as UI +import kotlinx.coroutines.experimental.javafx.JavaFx as Main import javafx.application.Application import javafx.event.EventHandler import javafx.geometry.* @@ -51,7 +51,7 @@ class ExampleApp : Application() { } fun Node.onClick(action: suspend (MouseEvent) -> Unit) { - val eventActor = actor(UI, capacity = Channel.CONFLATED) { + val eventActor = actor(Dispatchers.Main, capacity = Channel.CONFLATED) { for (event in channel) action(event) // pass event to action } onMouseClicked = EventHandler { event -> @@ -62,7 +62,7 @@ fun Node.onClick(action: suspend (MouseEvent) -> Unit) { fun setup(hello: Text, fab: Circle) { var result = "none" // the last result // counting animation - GlobalScope.launch(UI) { + GlobalScope.launch(Dispatchers.Main) { var counter = 0 while (true) { hello.text = "${++counter}: $result" @@ -77,6 +77,6 @@ fun setup(hello: Text, fab: Circle) { } } -suspend fun fib(x: Int): Int = withContext(CommonPool) { +suspend fun fib(x: Int): Int = withContext(Dispatchers.Default) { if (x <= 1) x else fib(x - 1) + fib(x - 2) } diff --git a/ui/kotlinx-coroutines-javafx/test/guide/example-ui-blocking-03.kt b/ui/kotlinx-coroutines-javafx/test/guide/example-ui-blocking-03.kt index 3422fd3b76..0952931065 100644 --- a/ui/kotlinx-coroutines-javafx/test/guide/example-ui-blocking-03.kt +++ b/ui/kotlinx-coroutines-javafx/test/guide/example-ui-blocking-03.kt @@ -7,7 +7,7 @@ package kotlinx.coroutines.experimental.javafx.guide.blocking03 import kotlinx.coroutines.experimental.* import kotlinx.coroutines.experimental.channels.* -import kotlinx.coroutines.experimental.javafx.JavaFx as UI +import kotlinx.coroutines.experimental.javafx.JavaFx as Main import javafx.application.Application import javafx.event.EventHandler import javafx.geometry.* @@ -51,7 +51,7 @@ class ExampleApp : Application() { } fun Node.onClick(action: suspend (MouseEvent) -> Unit) { - val eventActor = actor(UI, capacity = Channel.CONFLATED) { + val eventActor = actor(Dispatchers.Main, capacity = Channel.CONFLATED) { for (event in channel) action(event) // pass event to action } onMouseClicked = EventHandler { event -> @@ -62,7 +62,7 @@ fun Node.onClick(action: suspend (MouseEvent) -> Unit) { fun setup(hello: Text, fab: Circle) { var result = "none" // the last result // counting animation - GlobalScope.launch(UI) { + GlobalScope.launch(Dispatchers.Main) { var counter = 0 while (true) { hello.text = "${++counter}: $result" @@ -77,7 +77,7 @@ fun setup(hello: Text, fab: Circle) { } } -suspend fun fib(x: Int): Int = withContext(CommonPool) { +suspend fun fib(x: Int): Int = withContext(Dispatchers.Default) { fibBlocking(x) } diff --git a/ui/kotlinx-coroutines-swing/src/Swing.kt b/ui/kotlinx-coroutines-swing/src/SwingDispatcher.kt similarity index 59% rename from ui/kotlinx-coroutines-swing/src/Swing.kt rename to ui/kotlinx-coroutines-swing/src/SwingDispatcher.kt index 304993c287..8ee7761ff8 100644 --- a/ui/kotlinx-coroutines-swing/src/Swing.kt +++ b/ui/kotlinx-coroutines-swing/src/SwingDispatcher.kt @@ -4,21 +4,37 @@ package kotlinx.coroutines.experimental.swing -import kotlinx.coroutines.experimental.CancellableContinuation -import kotlinx.coroutines.experimental.CoroutineDispatcher -import kotlinx.coroutines.experimental.Delay -import kotlinx.coroutines.experimental.DisposableHandle +import kotlinx.coroutines.experimental.* import kotlinx.coroutines.experimental.swing.Swing.delay -import java.awt.event.ActionListener -import java.util.concurrent.TimeUnit -import javax.swing.SwingUtilities -import javax.swing.Timer -import kotlin.coroutines.experimental.CoroutineContext +import java.awt.event.* +import java.util.concurrent.* +import javax.swing.* +import kotlin.coroutines.experimental.* /** * Dispatches execution onto Swing event dispatching thread and provides native [delay] support. */ -object Swing : CoroutineDispatcher(), Delay { +public val Dispatchers.Swing : SwingDispatcher + get() = kotlinx.coroutines.experimental.swing.Swing + +/** + * Dispatcher for Swing event dispatching thread. + * + * This class provides type-safety and a point for future extensions. + */ +public sealed class SwingDispatcher : CoroutineDispatcher(), Delay + +/** + * Dispatches execution onto Swing event dispatching thread and provides native [delay] support. + * @suppress **Deprecated**: Use [Dispatchers.Swing]. + */ +@Deprecated( + message = "Use Dispatchers.Swing", + replaceWith = ReplaceWith("Dispatchers.Swing", + imports = ["kotlinx.coroutines.experimental.Dispatchers", "kotlinx.coroutines.experimental.swing.Swing"]) +) +// todo: it will become an internal implementation object +object Swing : SwingDispatcher(), Delay { override fun dispatch(context: CoroutineContext, block: Runnable) = SwingUtilities.invokeLater(block) override fun scheduleResumeAfterDelay(time: Long, unit: TimeUnit, continuation: CancellableContinuation) { diff --git a/ui/kotlinx-coroutines-swing/test/SwingTest.kt b/ui/kotlinx-coroutines-swing/test/SwingTest.kt index 86f5a70ba9..f15abbd51a 100644 --- a/ui/kotlinx-coroutines-swing/test/SwingTest.kt +++ b/ui/kotlinx-coroutines-swing/test/SwingTest.kt @@ -5,9 +5,8 @@ package kotlinx.coroutines.experimental.swing import kotlinx.coroutines.experimental.* -import org.junit.Before -import org.junit.Test -import javax.swing.SwingUtilities +import org.junit.* +import javax.swing.* class SwingTest : TestBase() { @Before @@ -19,7 +18,7 @@ class SwingTest : TestBase() { fun testDelay() = runBlocking { expect(1) SwingUtilities.invokeLater { expect(2) } - val job = launch(Swing) { + val job = launch(Dispatchers.Swing) { check(SwingUtilities.isEventDispatchThread()) expect(3) SwingUtilities.invokeLater { expect(4) } diff --git a/ui/kotlinx-coroutines-swing/test/examples/SwingExampleApp.kt b/ui/kotlinx-coroutines-swing/test/examples/SwingExampleApp.kt index adf26c5844..aeefd082db 100644 --- a/ui/kotlinx-coroutines-swing/test/examples/SwingExampleApp.kt +++ b/ui/kotlinx-coroutines-swing/test/examples/SwingExampleApp.kt @@ -33,7 +33,7 @@ private fun createAndShowGUI() { frame.pack() frame.isVisible = true - GlobalScope.launch(Swing) { + GlobalScope.launch(Dispatchers.Swing) { for (i in 1..10) { // 'append' method and consequent 'jProgressBar.setValue' are called // within Swing event dispatch thread diff --git a/ui/kotlinx-coroutines-swing/test/examples/swing-example.kt b/ui/kotlinx-coroutines-swing/test/examples/swing-example.kt index 1e1e5c6885..d3e0784d0d 100644 --- a/ui/kotlinx-coroutines-swing/test/examples/swing-example.kt +++ b/ui/kotlinx-coroutines-swing/test/examples/swing-example.kt @@ -4,12 +4,12 @@ package examples -import kotlinx.coroutines.experimental.runBlocking -import kotlinx.coroutines.experimental.swing.Swing -import java.text.SimpleDateFormat +import kotlinx.coroutines.experimental.* +import kotlinx.coroutines.experimental.swing.* +import java.text.* import java.util.* -import java.util.concurrent.ForkJoinPool -import kotlin.coroutines.experimental.suspendCoroutine +import java.util.concurrent.* +import kotlin.coroutines.experimental.* fun log(msg: String) = println("${SimpleDateFormat("yyyyMMdd-HHmmss.sss").format(Date())} [${Thread.currentThread().name}] $msg") @@ -26,7 +26,7 @@ fun display(result: String) { log("Displaying result '$result'") } -fun main(args: Array) = runBlocking(Swing) { +fun main(args: Array) = runBlocking(Dispatchers.Swing) { try { // suspend while asynchronously making request val result = makeRequest() From b1e89ef6253e242fc53b257ff5de53e31802e7fc Mon Sep 17 00:00:00 2001 From: Roman Elizarov Date: Tue, 11 Sep 2018 19:16:49 +0300 Subject: [PATCH 2/3] Updated dispatchers references in readmes and docs --- README.md | 10 ++++------ .../src/CoroutineScope.kt | 20 +++++++++---------- core/kotlinx-coroutines-core/README.md | 10 +++++----- .../src/ThreadContextElement.kt | 2 +- .../test/ThreadContextElementTest.kt | 2 +- .../test/ThreadLocalTest.kt | 12 +++++------ js/kotlinx-coroutines-core-js/README.md | 9 +++++---- .../kotlinx-coroutines-core-native/README.md | 7 ++++--- reactive/coroutines-guide-reactive.md | 11 +++++----- .../test/guide/example-reactive-context-02.kt | 2 +- .../test/guide/example-reactive-context-03.kt | 2 +- ui/README.md | 6 +++--- ui/coroutines-guide-ui.md | 10 +++++++--- ui/kotlinx-coroutines-android/README.md | 2 +- ui/kotlinx-coroutines-javafx/README.md | 2 +- ui/kotlinx-coroutines-swing/README.md | 2 +- 16 files changed, 56 insertions(+), 53 deletions(-) diff --git a/README.md b/README.md index 9e372d8513..ea167e5bb5 100644 --- a/README.md +++ b/README.md @@ -8,7 +8,7 @@ Library support for Kotlin coroutines with [multiplatform](#multiplatform) suppo This is a companion version for Kotlin 1.2.61 release. ```kotlin -launch { +GlobalScope.launch { delay(1000) println("Hello from Kotlin Coroutines!") } @@ -19,14 +19,12 @@ launch { * [common](common/README.md) — common coroutines across all backends: * `launch` and `async` coroutine builders; * `Job` and `Deferred` light-weight future with cancellation support; - * `delay` and `yield` top-level suspending functions. + * `delay` and `yield` top-level suspending functions; * `Channel` and `Mutex` communication and synchronization primitives; - * `produce` coroutine builder; + * `produce` and `actor` coroutine builders; * `select` expression support and more. * [core](core/README.md) — Kotlin/JVM implementation of common coroutines with additional features: - * `CommonPool` coroutine context (default on JVM); - * `actor` coroutine builder; - * `IO` dispatcher for blocking coroutines + * `Dispatchers.IO` dispatcher for blocking coroutines. * [js](js/README.md) — Kotlin/JS implementation of common coroutines with `Promise` support. * [native](native/README.md) — Kotlin/Native implementation of common coroutines with `runBlocking` single-threaded event loop. * [reactive](reactive/README.md) — modules that provide builders and iteration support for various reactive streams libraries: diff --git a/common/kotlinx-coroutines-core-common/src/CoroutineScope.kt b/common/kotlinx-coroutines-core-common/src/CoroutineScope.kt index b15dca70b9..4de0f7a1aa 100644 --- a/common/kotlinx-coroutines-core-common/src/CoroutineScope.kt +++ b/common/kotlinx-coroutines-core-common/src/CoroutineScope.kt @@ -18,9 +18,9 @@ import kotlin.coroutines.experimental.* * * ``` * class MyActivity : AppCompatActivity(), CoroutineScope { - * + * lateinit var job: Job * override val coroutineContext: CoroutineContext - * get() = job + UI + * get() = Dispatchers.Main + job * * override fun onCreate(savedInstanceState: Bundle?) { * super.onCreate(savedInstanceState) @@ -34,17 +34,15 @@ import kotlin.coroutines.experimental.* * * /* * * Note how coroutine builders are scoped: if activity is destroyed or any of the launched coroutines - * * in this method throws an exception, then all nested coroutines will be cancelled. + * * in this method throws an exception, then all nested coroutines are cancelled. * */ - * fun loadDataFromUI() = launch { // <- extension on current activity, launched in CommonPool - * val ioData = async(IO) { // <- extension on launch scope, launched in IO dispatcher - * // long computation - * } - * - * withContext(UI) { - * val data = ioData.await() - * draw(data) + * fun loadDataFromUI() = launch { // <- extension on current activity, launched in the main thread + * val ioData = async(Dispatchers.IO) { // <- extension on launch scope, launched in IO dispatcher + * // blocking I/O operation * } + * // do something else concurrently with I/O + * val data = ioData.await() // wait for result of I/O + * draw(data) // can draw in the main thread * } * } * diff --git a/core/kotlinx-coroutines-core/README.md b/core/kotlinx-coroutines-core/README.md index bd30844e9a..f2b9977531 100644 --- a/core/kotlinx-coroutines-core/README.md +++ b/core/kotlinx-coroutines-core/README.md @@ -16,12 +16,11 @@ Coroutine dispatchers implementing [CoroutineDispatcher]: | **Name** | **Description** | --------------------------- | --------------- -| [DefaultDispatcher] | Is equal to [CommonPool] -| [CommonPool] | Confines coroutine execution to a shared pool of threads +| [Dispatchers.Default] | Confines coroutine execution to a shared pool of background threads +| [Dispatchers.Unconfined] | Does not confine coroutine execution in any way | [newSingleThreadContext] | Create new single-threaded coroutine context | [newFixedThreadPoolContext] | Creates new thread pool of a fixed size | [Executor.asCoroutineDispatcher][java.util.concurrent.Executor.asCoroutineDispatcher] | Extension to convert any executor -| [Unconfined] | Does not confine coroutine execution in any way More context elements: @@ -51,7 +50,7 @@ Top-level suspending functions: Cancellation support for user-defined suspending functions is available with [suspendCancellableCoroutine] helper function. [NonCancellable] job object is provided to suppress cancellation with -`run(NonCancellable) {...}` block of code. +`withContext(NonCancellable) {...}` block of code. [Select][kotlinx.coroutines.experimental.selects.select] expression waits for the result of multiple suspending functions simultaneously: @@ -110,7 +109,8 @@ Components to ease writing unit-tests for code that contains coroutines with del [Deferred]: https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines.experimental/-deferred/index.html [runBlocking]: https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines.experimental/run-blocking.html [CoroutineDispatcher]: https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines.experimental/-coroutine-dispatcher/index.html -[DefaultDispatcher]: https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines.experimental/-default-dispatcher.html +[Dispatchers.Default]: https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines.experimental/-dispatchers/-default.html +[Dispatchers.Unconfined]: https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines.experimental/-dispatchers/-unconfined.html [newSingleThreadContext]: https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines.experimental/new-single-thread-context.html [newFixedThreadPoolContext]: https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines.experimental/new-fixed-thread-pool-context.html [java.util.concurrent.Executor.asCoroutineDispatcher]: https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines.experimental/java.util.concurrent.-executor/as-coroutine-dispatcher.html diff --git a/core/kotlinx-coroutines-core/src/ThreadContextElement.kt b/core/kotlinx-coroutines-core/src/ThreadContextElement.kt index d5e8b74af0..d1222df5b9 100644 --- a/core/kotlinx-coroutines-core/src/ThreadContextElement.kt +++ b/core/kotlinx-coroutines-core/src/ThreadContextElement.kt @@ -84,7 +84,7 @@ public interface ThreadContextElement : CoroutineContext.Element { * val myThreadLocal = ThreadLocal() * ... * println(myThreadLocal.get()) // Prints "null" - * launch(CommonPool + myThreadLocal.asContextElement(value = "foo")) { + * launch(Dispatchers.Default + myThreadLocal.asContextElement(value = "foo")) { * println(myThreadLocal.get()) // Prints "foo" * withContext(UI) { * println(myThreadLocal.get()) // Prints "foo", but it's on UI thread diff --git a/core/kotlinx-coroutines-core/test/ThreadContextElementTest.kt b/core/kotlinx-coroutines-core/test/ThreadContextElementTest.kt index c19ba2bcc5..223abcc368 100644 --- a/core/kotlinx-coroutines-core/test/ThreadContextElementTest.kt +++ b/core/kotlinx-coroutines-core/test/ThreadContextElementTest.kt @@ -60,7 +60,7 @@ class ThreadContextElementTest : TestBase() { expect(1) newSingleThreadContext("withContext").use { val data = MyData() - GlobalScope.async(CommonPool + MyElement(data)) { + GlobalScope.async(Dispatchers.Default + MyElement(data)) { assertSame(data, myThreadLocal.get()) expect(2) diff --git a/core/kotlinx-coroutines-core/test/ThreadLocalTest.kt b/core/kotlinx-coroutines-core/test/ThreadLocalTest.kt index b535a629de..cd474cf9ad 100644 --- a/core/kotlinx-coroutines-core/test/ThreadLocalTest.kt +++ b/core/kotlinx-coroutines-core/test/ThreadLocalTest.kt @@ -22,7 +22,7 @@ class ThreadLocalTest : TestBase() { @Test fun testThreadLocal() = runTest { assertNull(stringThreadLocal.get()) - val deferred = async(CommonPool + stringThreadLocal.asContextElement("value")) { + val deferred = async(Dispatchers.Default + stringThreadLocal.asContextElement("value")) { assertEquals("value", stringThreadLocal.get()) withContext(executor) { assertEquals("value", stringThreadLocal.get()) @@ -38,7 +38,7 @@ class ThreadLocalTest : TestBase() { @Test fun testThreadLocalInitialValue() = runTest { intThreadLocal.set(42) - val deferred = async(CommonPool + intThreadLocal.asContextElement(239)) { + val deferred = async(Dispatchers.Default + intThreadLocal.asContextElement(239)) { assertEquals(239, intThreadLocal.get()) withContext(executor) { assertEquals(239, intThreadLocal.get()) @@ -55,7 +55,7 @@ class ThreadLocalTest : TestBase() { stringThreadLocal.set("test") intThreadLocal.set(314) - val deferred = async(CommonPool + val deferred = async(Dispatchers.Default + intThreadLocal.asContextElement(value = 239) + stringThreadLocal.asContextElement(value = "pew")) { assertEquals(239, intThreadLocal.get()) assertEquals("pew", stringThreadLocal.get()) @@ -110,7 +110,7 @@ class ThreadLocalTest : TestBase() { fun testThreadLocalModification() = runTest { stringThreadLocal.set("main") - val deferred = async(CommonPool + val deferred = async(Dispatchers.Default + stringThreadLocal.asContextElement("initial")) { assertEquals("initial", stringThreadLocal.get()) @@ -141,7 +141,7 @@ class ThreadLocalTest : TestBase() { fun testThreadLocalModificationMutableBox() = runTest { myCounterLocal.set(Counter(42)) - val deferred = async(CommonPool + val deferred = async(Dispatchers.Default + myCounterLocal.asContextElement(Counter(0))) { assertEquals(0, myCounterLocal.get().cnt) @@ -171,7 +171,7 @@ class ThreadLocalTest : TestBase() { expect(1) newSingleThreadContext("withContext").use { val data = 42 - GlobalScope.async(CommonPool + intThreadLocal.asContextElement(42)) { + GlobalScope.async(Dispatchers.Default + intThreadLocal.asContextElement(42)) { assertSame(data, intThreadLocal.get()) expect(2) diff --git a/js/kotlinx-coroutines-core-js/README.md b/js/kotlinx-coroutines-core-js/README.md index caad05b610..a4dff92203 100644 --- a/js/kotlinx-coroutines-core-js/README.md +++ b/js/kotlinx-coroutines-core-js/README.md @@ -14,8 +14,8 @@ Coroutine dispatchers implementing [CoroutineDispatcher]: | **Name** | **Description** | --------------------------- | --------------- -| [DefaultDispatcher] | Posts execution to JS event loop -| [Unconfined] | Does not confine coroutine execution in any way +| [Dispatchers.Default] | Posts execution to JS event loop +| [Dispatchers.Unconfined] | Does not confine coroutine execution in any way More context elements: @@ -45,7 +45,7 @@ Top-level suspending functions: Cancellation support for user-defined suspending functions is available with [suspendCancellableCoroutine] helper function. [NonCancellable] job object is provided to suppress cancellation with -`run(NonCancellable) {...}` block of code. +`withContext(NonCancellable) {...}` block of code. [Select][kotlinx.coroutines.experimental.selects.select] expression waits for the result of multiple suspending functions simultaneously: @@ -67,7 +67,8 @@ helper function. [NonCancellable] job object is provided to suppress cancellatio [async]: https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines.experimental/async.html [Deferred]: https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines.experimental/-deferred/index.html [CoroutineDispatcher]: https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines.experimental/-coroutine-dispatcher/index.html -[DefaultDispatcher]: https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines.experimental/-default-dispatcher.html +[Dispatchers.Default]: https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines.experimental/-dispatchers/-default.html +[Dispatchers.Unconfined]: https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines.experimental/-dispatchers/-unconfined.html [NonCancellable]: https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines.experimental/-non-cancellable/index.html [CoroutineExceptionHandler]: https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines.experimental/-coroutine-exception-handler/index.html [delay]: https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines.experimental/delay.html diff --git a/native/kotlinx-coroutines-core-native/README.md b/native/kotlinx-coroutines-core-native/README.md index 68643c98f5..824268ac81 100644 --- a/native/kotlinx-coroutines-core-native/README.md +++ b/native/kotlinx-coroutines-core-native/README.md @@ -16,8 +16,8 @@ Coroutine dispatchers implementing [CoroutineDispatcher]: | **Name** | **Description** | --------------------------- | --------------- -| [DefaultDispatcher] | TBD -| [Unconfined] | Does not confine coroutine execution in any way +| [Dispatchers.Default] | References current [runBlocking] event loop +| [Dispatchers.Unconfined] | Does not confine coroutine execution in any way More context elements: @@ -70,7 +70,8 @@ helper function. [NonCancellable] job object is provided to suppress cancellatio [Deferred]: https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines.experimental/-deferred/index.html [runBlocking]: https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines.experimental/run-blocking.html [CoroutineDispatcher]: https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines.experimental/-coroutine-dispatcher/index.html -[DefaultDispatcher]: https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines.experimental/-default-dispatcher.html +[Dispatchers.Default]: https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines.experimental/-dispatchers/-default.html +[Dispatchers.Unconfined]: https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines.experimental/-dispatchers/-unconfined.html [NonCancellable]: https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines.experimental/-non-cancellable/index.html [CoroutineExceptionHandler]: https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines.experimental/-coroutine-exception-handler/index.html [delay]: https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines.experimental/delay.html diff --git a/reactive/coroutines-guide-reactive.md b/reactive/coroutines-guide-reactive.md index e706235dba..99692449c8 100644 --- a/reactive/coroutines-guide-reactive.md +++ b/reactive/coroutines-guide-reactive.md @@ -862,7 +862,7 @@ it is going to be executed in Rx computation thread pool. The output is going to ### Threads with coroutines -In the world of coroutines `Schedulers.computation()` roughly corresponds to [CommonPool], +In the world of coroutines `Schedulers.computation()` roughly corresponds to [Dispatchers.Default], so the previous example is similar to the following one: [Channel]: https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines.experimental.channels/-channel/index.html diff --git a/reactive/kotlinx-coroutines-rx2/test/guide/example-reactive-context-02.kt b/reactive/kotlinx-coroutines-rx2/test/guide/example-reactive-context-02.kt index 4d1df1a6cf..25a04aa184 100644 --- a/reactive/kotlinx-coroutines-rx2/test/guide/example-reactive-context-02.kt +++ b/reactive/kotlinx-coroutines-rx2/test/guide/example-reactive-context-02.kt @@ -18,7 +18,7 @@ fun rangeWithInterval(context: CoroutineContext, time: Long, start: Int, count: } fun main(args: Array) { - Flowable.fromPublisher(rangeWithInterval(CommonPool, 100, 1, 3)) + Flowable.fromPublisher(rangeWithInterval(Dispatchers.Default, 100, 1, 3)) .subscribe { println("$it on thread ${Thread.currentThread().name}") } Thread.sleep(1000) } diff --git a/reactive/kotlinx-coroutines-rx2/test/guide/example-reactive-context-03.kt b/reactive/kotlinx-coroutines-rx2/test/guide/example-reactive-context-03.kt index b92d00fdcb..be55df3c8c 100644 --- a/reactive/kotlinx-coroutines-rx2/test/guide/example-reactive-context-03.kt +++ b/reactive/kotlinx-coroutines-rx2/test/guide/example-reactive-context-03.kt @@ -19,7 +19,7 @@ fun rangeWithInterval(context: CoroutineContext, time: Long, start: Int, count: } fun main(args: Array) { - Flowable.fromPublisher(rangeWithInterval(CommonPool, 100, 1, 3)) + Flowable.fromPublisher(rangeWithInterval(Dispatchers.Default, 100, 1, 3)) .observeOn(Schedulers.computation()) // <-- THIS LINE IS ADDED .subscribe { println("$it on thread ${Thread.currentThread().name}") } Thread.sleep(1000) diff --git a/ui/README.md b/ui/README.md index 18beacbd77..db5b92d562 100644 --- a/ui/README.md +++ b/ui/README.md @@ -5,6 +5,6 @@ Module name below corresponds to the artifact name in Maven/Gradle. ## Modules -* [kotlinx-coroutines-android](kotlinx-coroutines-android/README.md) -- `UI` context for Android applications. -* [kotlinx-coroutines-javafx](kotlinx-coroutines-javafx/README.md) -- `JavaFx` context for JavaFX UI applications. -* [kotlinx-coroutines-swing](kotlinx-coroutines-swing/README.md) -- `Swing` context for Swing UI applications. +* [kotlinx-coroutines-android](kotlinx-coroutines-android/README.md) -- `Dispatchers.Main` context for Android applications. +* [kotlinx-coroutines-javafx](kotlinx-coroutines-javafx/README.md) -- `Dispatchers.JavaFx` context for JavaFX UI applications. +* [kotlinx-coroutines-swing](kotlinx-coroutines-swing/README.md) -- `Dispatchers.Swing` context for Swing UI applications. diff --git a/ui/coroutines-guide-ui.md b/ui/coroutines-guide-ui.md index 20d9974ca4..fbf753c835 100644 --- a/ui/coroutines-guide-ui.md +++ b/ui/coroutines-guide-ui.md @@ -182,7 +182,9 @@ This section shows basic usage of coroutines in UI applications. ### Launch UI coroutine -The `kotlinx-coroutines-javafx` module contains [Dispatchers.JavaFx] dispatcher that dispatches coroutine execution to +The `kotlinx-coroutines-javafx` module contains +[Dispatchers.JavaFx][kotlinx.coroutines.experimental.Dispatchers.JavaFx] +dispatcher that dispatches coroutine execution to the JavaFx application thread. We import it as `Main` to make all the presented examples easily portable to Android: @@ -555,7 +557,7 @@ when the parent job is cancelled. An example of that is shown in the The fix for the blocking operations on the main UI thread is quite straightforward with coroutines. We'll convert our "blocking" `fib` function to a non-blocking suspending function that runs the computation in -the background thread by using [withContext] function to change its execution context to [Dispathers.Default] that is +the background thread by using [withContext] function to change its execution context to [Dispatchers.Default] that is backed by the background pool of threads. Notice, that `fib` function is now marked with `suspend` modifier. It does not block the coroutine that it is invoked from anymore, but suspends its execution when the computation in the background thread is working: @@ -633,7 +635,7 @@ from the UI thread: fun setup(hello: Text, fab: Circle) { fab.onMouseClicked = EventHandler { println("Before launch") - GlobalScope.launch(Dispatchers.Main) { + GlobalScope.launch(Dispatchers.Main) { println("Inside coroutine") delay(100) println("After delay") @@ -705,6 +707,7 @@ After delay [CoroutineScope]: https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines.experimental/-coroutine-scope/index.html [currentScope]: https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines.experimental/current-scope.html [withContext]: https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines.experimental/with-context.html +[Dispatchers.Default]: https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines.experimental/-dispatchers/-default.html [CoroutineStart]: https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines.experimental/-coroutine-start/index.html [async]: https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines.experimental/async.html [CoroutineStart.UNDISPATCHED]: https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines.experimental/-coroutine-start/-u-n-d-i-s-p-a-t-c-h-e-d.html @@ -719,6 +722,7 @@ After delay [LinkedListChannel]: https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines.experimental.channels/-linked-list-channel/index.html +[kotlinx.coroutines.experimental.Dispatchers.JavaFx]: https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-javafx/kotlinx.coroutines.experimental.javafx/kotlinx.coroutines.experimental.-dispatchers/-java-fx.html diff --git a/ui/kotlinx-coroutines-android/README.md b/ui/kotlinx-coroutines-android/README.md index 8bbbdc70a5..d26a5a2faf 100644 --- a/ui/kotlinx-coroutines-android/README.md +++ b/ui/kotlinx-coroutines-android/README.md @@ -7,4 +7,4 @@ for tutorial on this module. # Package kotlinx.coroutines.experimental.android -Provides `UI` context for Android applications. +Provides `Dispatchers.Main` context for Android applications. diff --git a/ui/kotlinx-coroutines-javafx/README.md b/ui/kotlinx-coroutines-javafx/README.md index 1dba74e250..e894077338 100644 --- a/ui/kotlinx-coroutines-javafx/README.md +++ b/ui/kotlinx-coroutines-javafx/README.md @@ -7,4 +7,4 @@ for tutorial on this module. # Package kotlinx.coroutines.experimental.javafx -Provides `JavaFx` context for JavaFX UI applications. +Provides `Dispatchers.JavaFx` context for JavaFX UI applications. diff --git a/ui/kotlinx-coroutines-swing/README.md b/ui/kotlinx-coroutines-swing/README.md index a035928be6..a09b01a9df 100644 --- a/ui/kotlinx-coroutines-swing/README.md +++ b/ui/kotlinx-coroutines-swing/README.md @@ -7,4 +7,4 @@ for tutorial on this module. # Package kotlinx.coroutines.experimental.swing -Provides `Swing` context for Swing UI applications. +Provides `Dispatchers.Swing` context for Swing UI applications. From c21f7c92d79874b52e600fadac2eeee726028760 Mon Sep 17 00:00:00 2001 From: Vsevolod Tolstopyatov Date: Tue, 11 Sep 2018 19:57:08 +0300 Subject: [PATCH 3/3] Restore backward compatibility --- .../kotlinx-coroutines-android.txt | 7 ++++-- .../src/Dispatchers.common.kt | 4 --- .../src/channels/Broadcast.kt | 3 +-- .../src/Dispatchers.kt | 2 ++ .../src/HandlerContext.kt | 25 +++++++++++++++++++ .../src/HandlerDispatcher.kt | 19 ++------------ 6 files changed, 35 insertions(+), 25 deletions(-) create mode 100644 ui/kotlinx-coroutines-android/src/HandlerContext.kt diff --git a/binary-compatibility-validator/reference-public-api/kotlinx-coroutines-android.txt b/binary-compatibility-validator/reference-public-api/kotlinx-coroutines-android.txt index 41843a6be6..d8ed275ee1 100644 --- a/binary-compatibility-validator/reference-public-api/kotlinx-coroutines-android.txt +++ b/binary-compatibility-validator/reference-public-api/kotlinx-coroutines-android.txt @@ -18,6 +18,11 @@ public final class kotlinx/coroutines/experimental/android/HandlerContext : kotl public fun toString ()Ljava/lang/String; } +public final class kotlinx/coroutines/experimental/android/HandlerContextKt { + public static final synthetic fun asCoroutineDispatcher (Landroid/os/Handler;)Lkotlinx/coroutines/experimental/android/HandlerContext; + public static final fun getUI ()Lkotlinx/coroutines/experimental/android/HandlerContext; +} + public abstract class kotlinx/coroutines/experimental/android/HandlerDispatcher : kotlinx/coroutines/experimental/CoroutineDispatcher, kotlinx/coroutines/experimental/Delay { public fun delay (JLjava/util/concurrent/TimeUnit;Lkotlin/coroutines/experimental/Continuation;)Ljava/lang/Object; public abstract fun getImmediate ()Lkotlinx/coroutines/experimental/android/HandlerDispatcher; @@ -25,10 +30,8 @@ public abstract class kotlinx/coroutines/experimental/android/HandlerDispatcher } public final class kotlinx/coroutines/experimental/android/HandlerDispatcherKt { - public static final synthetic fun asCoroutineDispatcher (Landroid/os/Handler;)Lkotlinx/coroutines/experimental/android/HandlerContext; public static final fun asCoroutineDispatcher (Landroid/os/Handler;)Lkotlinx/coroutines/experimental/android/HandlerDispatcher; public static final fun awaitFrame (Lkotlin/coroutines/experimental/Continuation;)Ljava/lang/Object; public static final fun getMain (Lkotlinx/coroutines/experimental/Dispatchers;)Lkotlinx/coroutines/experimental/android/HandlerDispatcher; - public static final fun getUI ()Lkotlinx/coroutines/experimental/android/HandlerContext; } diff --git a/common/kotlinx-coroutines-core-common/src/Dispatchers.common.kt b/common/kotlinx-coroutines-core-common/src/Dispatchers.common.kt index 6528c2b597..68b6010537 100644 --- a/common/kotlinx-coroutines-core-common/src/Dispatchers.common.kt +++ b/common/kotlinx-coroutines-core-common/src/Dispatchers.common.kt @@ -2,10 +2,6 @@ * Copyright 2016-2018 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license. */ -/* - * Copyright 2016-2018 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license. - */ - package kotlinx.coroutines.experimental import kotlinx.coroutines.experimental.internal.* diff --git a/common/kotlinx-coroutines-core-common/src/channels/Broadcast.kt b/common/kotlinx-coroutines-core-common/src/channels/Broadcast.kt index 097816d358..c35e39a4e4 100644 --- a/common/kotlinx-coroutines-core-common/src/channels/Broadcast.kt +++ b/common/kotlinx-coroutines-core-common/src/channels/Broadcast.kt @@ -45,7 +45,7 @@ public fun broadcast( onCompletion: CompletionHandler? = null, block: suspend ProducerScope.() -> Unit ): BroadcastChannel = - GlobalScope.broadcast(context + (parent ?: Dispatchers.Default), capacity, start, onCompletion, block) + GlobalScope.broadcast(context + (parent ?: EmptyCoroutineContext), capacity, start, onCompletion, block) /** * Launches new coroutine to produce a stream of values by sending them to a broadcast channel @@ -141,4 +141,3 @@ private class LazyBroadcastCoroutine( block.startCoroutineCancellable(this, this) } } - diff --git a/core/kotlinx-coroutines-core/src/Dispatchers.kt b/core/kotlinx-coroutines-core/src/Dispatchers.kt index 2426af28f7..8c8a21057e 100644 --- a/core/kotlinx-coroutines-core/src/Dispatchers.kt +++ b/core/kotlinx-coroutines-core/src/Dispatchers.kt @@ -2,6 +2,8 @@ * Copyright 2016-2018 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license. */ +@file:Suppress("unused") + package kotlinx.coroutines.experimental import kotlinx.coroutines.experimental.scheduling.* diff --git a/ui/kotlinx-coroutines-android/src/HandlerContext.kt b/ui/kotlinx-coroutines-android/src/HandlerContext.kt new file mode 100644 index 0000000000..6a5b273f9f --- /dev/null +++ b/ui/kotlinx-coroutines-android/src/HandlerContext.kt @@ -0,0 +1,25 @@ +/* + * Copyright 2016-2018 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license. + */ + +package kotlinx.coroutines.experimental.android + +import android.os.* +import kotlinx.coroutines.experimental.* + +/** + * Dispatches execution onto Android main UI thread and provides native [delay][Delay.delay] support. + * @suppress **Deprecated**: Use [Dispatchers.Main]. + */ +@Deprecated( + message = "Use Dispatchers.Main", + replaceWith = ReplaceWith("Dispatchers.Main", + imports = ["kotlinx.coroutines.experimental.Dispatchers", "kotlinx.coroutines.experimental.android.Main"]) +) +val UI: HandlerContext + get() = Dispatchers.Main as HandlerContext + +@Deprecated(level = DeprecationLevel.HIDDEN, message = "Binary compatibility") +@JvmName("asCoroutineDispatcher") +public fun Handler.asCoroutineDispatcher0(): HandlerContext = + HandlerContext(this) diff --git a/ui/kotlinx-coroutines-android/src/HandlerDispatcher.kt b/ui/kotlinx-coroutines-android/src/HandlerDispatcher.kt index f9499a1f7b..453297a2ad 100644 --- a/ui/kotlinx-coroutines-android/src/HandlerDispatcher.kt +++ b/ui/kotlinx-coroutines-android/src/HandlerDispatcher.kt @@ -2,6 +2,8 @@ * Copyright 2016-2018 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license. */ +@file:Suppress("unused") + package kotlinx.coroutines.experimental.android import android.os.* @@ -36,23 +38,6 @@ public sealed class HandlerDispatcher : CoroutineDispatcher(), Delay { public fun Handler.asCoroutineDispatcher(): HandlerDispatcher = HandlerContext(this) -/** - * Dispatches execution onto Android main UI thread and provides native [delay][Delay.delay] support. - * @suppress **Deprecated**: Use [Dispatchers.Main]. - */ -@Deprecated( - message = "Use Dispatchers.Main", - replaceWith = ReplaceWith("Dispatchers.Main", - imports = ["kotlinx.coroutines.experimental.Dispatchers", "kotlinx.coroutines.experimental.android.Main"]) -) -val UI: HandlerContext - get() = mainDispatcher - -@Deprecated(level = DeprecationLevel.HIDDEN, message = "Binary compatibility") -@JvmName("asCoroutineDispatcher") -public fun Handler.asCoroutineDispatcher0(): HandlerContext = - HandlerContext(this) - private const val MAX_DELAY = Long.MAX_VALUE / 2 // cannot delay for too long on Android private val mainHandler = Handler(Looper.getMainLooper())