| /* |
| * Copyright 2016-2018 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license. |
| */ |
| |
| package kotlinx.coroutines |
| |
| import kotlin.coroutines.* |
| |
| /** |
| * Base class that shall be extended by all coroutine dispatcher implementations. |
| * |
| * The following standard implementations are provided by `kotlinx.coroutines` as properties on |
| * [Dispatchers] objects: |
| * |
| * * [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. |
| * * [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). |
| * * [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. |
| * **Unconfined dispatcher should not be normally used in code**. |
| * * Private thread pools can be created with [newSingleThreadContext] and [newFixedThreadPoolContext]. |
| * * An arbitrary [Executor][java.util.concurrent.Executor] can be converted to dispatcher with [asCoroutineDispatcher] extension function. |
| * |
| * This class ensures that debugging facilities in [newCoroutineContext] function work properly. |
| */ |
| public abstract class CoroutineDispatcher : |
| AbstractCoroutineContextElement(ContinuationInterceptor), ContinuationInterceptor { |
| /** |
| * Returns `true` if execution shall be dispatched onto another thread. |
| * The default behaviour for most dispatchers is to return `true`. |
| * |
| * This method should never be used from general code, it is used only by `kotlinx.coroutines` |
| * internals and its contract with the rest of API is an implementation detail. |
| * |
| * UI dispatchers _should not_ override `isDispatchNeeded`, but leave a default implementation that |
| * returns `true`. To understand the rationale beyond this recommendation, consider the following code: |
| * |
| * ```kotlin |
| * fun asyncUpdateUI() = async(Dispatchers.Main) { |
| * // do something here that updates something in UI |
| * } |
| * ``` |
| * |
| * When you invoke `asyncUpdateUI` in some background thread, it immediately continues to the next |
| * line, while UI update happens asynchronously in the UI thread. However, if you invoke |
| * it in the UI thread itself, it updates UI _synchronously_ if your `isDispatchNeeded` is |
| * overridden with a thread check. Checking if we are already in the UI thread seems more |
| * efficient (and it might indeed save a few CPU cycles), but this subtle and context-sensitive |
| * difference in behavior makes the resulting async code harder to debug. |
| * |
| * Basically, the choice here is between "JS-style" asynchronous approach (async actions |
| * are always postponed to be executed later in the even dispatch thread) and "C#-style" approach |
| * (async actions are executed in the invoker thread until the first suspension point). |
| * While, C# approach seems to be more efficient, it ends up with recommendations like |
| * "use `yield` if you need to ....". This is error-prone. JS-style approach is more consistent |
| * and does not require programmers to think about whether they need to yield or not. |
| * |
| * However, coroutine builders like [launch][CoroutineScope.launch] and [async][CoroutineScope.async] accept an optional [CoroutineStart] |
| * parameter that allows one to optionally choose C#-style [CoroutineStart.UNDISPATCHED] behaviour |
| * whenever it is needed for efficiency. |
| * |
| * This method should be generally exception-safe, an exception thrown from this method |
| * may leave the coroutines that use this dispatcher in the inconsistent and hard to debug state. |
| * |
| * **Note: This is an experimental api.** Execution semantics of coroutines may change in the future when this function returns `false`. |
| */ |
| @ExperimentalCoroutinesApi |
| public open fun isDispatchNeeded(context: CoroutineContext): Boolean = true |
| |
| /** |
| * Dispatches execution of a runnable [block] onto another thread in the given [context]. |
| * |
| * This method should be generally exception-safe, an exception thrown from this method |
| * may leave the coroutines that use this dispatcher in the inconsistent and hard to debug state. |
| */ |
| public abstract fun dispatch(context: CoroutineContext, block: Runnable) |
| |
| /** |
| * Dispatches execution of a runnable [block] onto another thread in the given [context] |
| * with a hint for dispatcher that current dispatch is triggered by [yield] call, so execution of this |
| * continuation may be delayed in favor of already dispatched coroutines. |
| * |
| * **Implementation note** though yield marker may be passed as a part of [context], this |
| * is a separate method for performance reasons |
| * |
| * @suppress **This an internal API and should not be used from general code.** |
| */ |
| @InternalCoroutinesApi |
| public open fun dispatchYield(context: CoroutineContext, block: Runnable) = dispatch(context, block) |
| |
| /** |
| * Returns continuation that wraps the original [continuation], thus intercepting all resumptions. |
| * |
| * This method should be generally exception-safe, an exception thrown from this method |
| * may leave the coroutines that use this dispatcher in the inconsistent and hard to debug state. |
| */ |
| public final override fun <T> interceptContinuation(continuation: Continuation<T>): Continuation<T> = |
| DispatchedContinuation(this, continuation) |
| |
| /** |
| * @suppress **Error**: Operator '+' on two CoroutineDispatcher objects is meaningless. |
| * CoroutineDispatcher is a coroutine context element and `+` is a set-sum operator for coroutine contexts. |
| * The dispatcher to the right of `+` just replaces the dispatcher the left of `+`. |
| */ |
| @Suppress("DeprecatedCallableAddReplaceWith") |
| @Deprecated( |
| message = "Operator '+' on two CoroutineDispatcher objects is meaningless. " + |
| "CoroutineDispatcher is a coroutine context element and `+` is a set-sum operator for coroutine contexts. " + |
| "The dispatcher to the right of `+` just replaces the dispatcher the left of `+`.", |
| level = DeprecationLevel.ERROR |
| ) |
| public operator fun plus(other: CoroutineDispatcher) = other |
| |
| /** @suppress for nicer debugging */ |
| override fun toString(): String = "$classSimpleName@$hexAddress" |
| } |
| |