blob: dc3fe1ce1f45c7943d47d8e3208a4265a76b1c1a [file] [log] [blame]
Roman Elizarovf16fd272017-02-07 11:26:00 +03001/*
Roman Elizarov1f74a2d2018-06-29 19:19:45 +03002 * Copyright 2016-2018 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
Roman Elizarovf16fd272017-02-07 11:26:00 +03003 */
4
Roman Elizarov3754f952017-01-18 20:47:54 +03005package kotlinx.coroutines.experimental
6
Roman Elizarovf29203c2018-01-11 12:39:36 +03007import kotlin.coroutines.experimental.*
Roman Elizarov3754f952017-01-18 20:47:54 +03008
9/**
Roman Elizaroved7b8642017-01-19 11:22:28 +030010 * Base class that shall be extended by all coroutine dispatcher implementations.
11 *
12 * The following standard implementations are provided by `kotlinx.coroutines`:
Roman Elizarov2f6d7c92017-02-03 15:16:07 +030013 * * [Unconfined] -- starts coroutine execution in the current call-frame until the first suspension.
14 * On first suspension the coroutine builder function returns.
15 * The coroutine will resume in whatever thread that is used by the
16 * corresponding suspending function, without confining it to any specific thread or pool.
Roman Elizaroved7b8642017-01-19 11:22:28 +030017 * This in an appropriate choice for IO-intensive coroutines that do not consume CPU resources.
Roman Elizarovc0d559b2017-09-28 14:27:05 +030018 * * [DefaultDispatcher] -- is used by all standard builder if no dispatcher nor any other [ContinuationInterceptor]
19 * is specified in their context. It is currently equal to [CommonPool] (subject to change).
Roman Elizaroved7b8642017-01-19 11:22:28 +030020 * * [CommonPool] -- immediately returns from the coroutine builder and schedules coroutine execution to
21 * a common pool of shared background threads.
22 * This is an appropriate choice for compute-intensive coroutines that consume a lot of CPU resources.
23 * * Private thread pools can be created with [newSingleThreadContext] and [newFixedThreadPoolContext].
Roman Elizarov38b5ea12017-03-09 12:03:39 +030024 * * An arbitrary [Executor][java.util.concurrent.Executor] can be converted to dispatcher with [asCoroutineDispatcher] extension function.
Roman Elizaroved7b8642017-01-19 11:22:28 +030025 *
Roman Elizarov44ba4b12017-01-25 11:37:54 +030026 * This class ensures that debugging facilities in [newCoroutineContext] function work properly.
Roman Elizarov3754f952017-01-18 20:47:54 +030027 */
Roman Elizarovaa461cf2018-04-11 13:20:29 +030028public abstract class CoroutineDispatcher :
Roman Elizarovf29203c2018-01-11 12:39:36 +030029 AbstractCoroutineContextElement(ContinuationInterceptor), ContinuationInterceptor {
Roman Elizarov3754f952017-01-18 20:47:54 +030030 /**
Roman Elizarova198bad2017-02-10 13:30:38 +030031 * Returns `true` if execution shall be dispatched onto another thread.
Roman Elizarov7cf452e2017-01-29 21:58:33 +030032 * The default behaviour for most dispatchers is to return `true`.
Roman Elizarova198bad2017-02-10 13:30:38 +030033 *
34 * UI dispatchers _should not_ override `isDispatchNeeded`, but leave a default implementation that
35 * returns `true`. To understand the rationale beyond this recommendation, consider the following code:
36 *
37 * ```kotlin
38 * fun asyncUpdateUI() = async(MainThread) {
39 * // do something here that updates something in UI
40 * }
41 * ```
42 *
43 * When you invoke `asyncUpdateUI` in some background thread, it immediately continues to the next
44 * line, while UI update happens asynchronously in the UI thread. However, if you invoke
45 * it in the UI thread itself, it updates UI _synchronously_ if your `isDispatchNeeded` is
46 * overridden with a thread check. Checking if we are already in the UI thread seems more
47 * efficient (and it might indeed save a few CPU cycles), but this subtle and context-sensitive
48 * difference in behavior makes the resulting async code harder to debug.
49 *
50 * Basically, the choice here is between "JS-style" asynchronous approach (async actions
51 * are always postponed to be executed later in the even dispatch thread) and "C#-style" approach
52 * (async actions are executed in the invoker thread until the first suspension point).
53 * While, C# approach seems to be more efficient, it ends up with recommendations like
54 * "use `yield` if you need to ....". This is error-prone. JS-style approach is more consistent
55 * and does not require programmers to think about whether they need to yield or not.
Roman Elizarovecda27f2017-04-06 23:06:26 +030056 *
57 * However, coroutine builders like [launch] and [async] accept an optional [CoroutineStart]
58 * parameter that allows one to optionally choose C#-style [CoroutineStart.UNDISPATCHED] behaviour
59 * whenever it is needed for efficiency.
Roman Elizarov3754f952017-01-18 20:47:54 +030060 */
Roman Elizarovaa461cf2018-04-11 13:20:29 +030061 public open fun isDispatchNeeded(context: CoroutineContext): Boolean = true
Roman Elizarov3754f952017-01-18 20:47:54 +030062
63 /**
Roman Elizarov67891d82017-01-23 16:47:20 +030064 * Dispatches execution of a runnable [block] onto another thread in the given [context].
Roman Elizarov3754f952017-01-18 20:47:54 +030065 */
Roman Elizarovaa461cf2018-04-11 13:20:29 +030066 public abstract fun dispatch(context: CoroutineContext, block: Runnable)
Roman Elizarov3754f952017-01-18 20:47:54 +030067
Roman Elizarovf138bbc2017-02-09 19:13:08 +030068 /**
69 * Returns continuation that wraps the original [continuation], thus intercepting all resumptions.
70 */
Roman Elizarovaa461cf2018-04-11 13:20:29 +030071 public override fun <T> interceptContinuation(continuation: Continuation<T>): Continuation<T> =
Roman Elizarovf29203c2018-01-11 12:39:36 +030072 DispatchedContinuation(this, continuation)
Roman Elizarov79a28682017-02-01 18:43:32 +030073
Roman Elizarov32d95322017-02-09 15:57:31 +030074 /**
Roman Elizarovfc7a9a22017-02-13 11:54:01 +030075 * @suppress **Error**: Operator '+' on two CoroutineDispatcher objects is meaningless.
Roman Elizarov32d95322017-02-09 15:57:31 +030076 * CoroutineDispatcher is a coroutine context element and `+` is a set-sum operator for coroutine contexts.
77 * The dispatcher to the right of `+` just replaces the dispatcher the left of `+`.
78 */
Roman Elizarov79a28682017-02-01 18:43:32 +030079 @Suppress("DeprecatedCallableAddReplaceWith")
Roman Elizarovf29203c2018-01-11 12:39:36 +030080 @Deprecated(
81 message = "Operator '+' on two CoroutineDispatcher objects is meaningless. " +
Roman Elizarov79a28682017-02-01 18:43:32 +030082 "CoroutineDispatcher is a coroutine context element and `+` is a set-sum operator for coroutine contexts. " +
Roman Elizarov32d95322017-02-09 15:57:31 +030083 "The dispatcher to the right of `+` just replaces the dispatcher the left of `+`.",
Roman Elizarovf29203c2018-01-11 12:39:36 +030084 level = DeprecationLevel.ERROR
85 )
Roman Elizarov79a28682017-02-01 18:43:32 +030086 public operator fun plus(other: CoroutineDispatcher) = other
Roman Elizarovdc9fd1c2017-04-07 10:35:28 +030087
88 // for nicer debugging
Roman Elizarovaa461cf2018-04-11 13:20:29 +030089 override fun toString(): String = "$classSimpleName@$hexAddress"
Roman Elizarov3754f952017-01-18 20:47:54 +030090}
91