Description
This is write-up on why kotlinx.coroutines
needs a DefaultDispatcher
and what it is.
The plan is to have a default value of context
parameter for all coroutine builders that are defined in kotlinx.coroutines
, so that instead of launch(someContext) { ... }
we can just write launch { ... }
unless we really care what context our coroutine runs in. Moreover, sometimes we only care about non-dispatch aspects of our coroutines and write launch(CoroutineName("foo")) { ... }
which does not really work as of now (see #133). We need some clearly defined default dispatcher that would be used in this case.
This is especially important in light of our effort to bring kotlinx.coroutines
into Kotlin/JS and Kotlin/Native code in such a way as writing common code with coroutines becomes possible. In common code we cannot write launch (CommonPool) { ... }
since the CommonPool
is defined only in Kotlin/JVM and is meaningless on other platforms due to different threading model. However, each platform can provide its own sensible default dispatcher.
We are going to define a top-level val in kotlinx.coroutines.experimental
package:
val DefaultDispatcher: CoroutineDispatcher = ...
There are a few questions to be answered here :
-
The type. We can use both
CoroutineContext
andCoroutineDispatcher
as types of that variable. The latter is preferable, since it would clearly highlight that it provides default dispatching logic and would prevent some obvious mistakes likeDefaultDispatcher + UI
(it will get flagged as an error during compilation, because adding two dispatchers does not make sense, as the later overwrites the former). -
The name.
DefaultDispatcher
looks good, since it clearly explains the purpose and fits the type. TheCaptilazationOfTheName is choosen for consistency with other dispatcher names likeUI
andCommonPool
, which are singletons.DefaultDispatcher
is also a singleton, so it is named as such. Of course, there is some bike-shedding to be held on how it all shall be named (see also CoroutineDispatcher's names #41), but we'll skip that bike-shedding for now, since the name ofDefaultDispatcher
is not going to actually appear in the source of end-user applications. -
The value. For Kotlin/JVM we'll start with
CommonPool
as the value ofDefaultDispatcher
. It is absolutely non-ideal value, since CommonPool is ill suited for the tasks that do not have recursive fork-join structure and most typical coroutine benchmarks run approximately 2 times faster in a single-threaded dispatcher than in CommonPool. Moreover, with CommonPool we cannot efficiently support blocking operations without having to switch to a different thread (see IO thread pool for blocking calls #79). Ultimately, a totally new, engineered from group-up implementation will be needed, but we'll leave this implementation for later.