https://kotlinlang.org logo
#coroutines
Title
# coroutines
j

JP

03/16/2020, 9:37 AM
https://play.kotlinlang.org/hands-on/Introduction%20to%20Coroutines%20and%20Channels/05_Concurrency
Run the code and check the log; we can see that all the coroutines still run on the main UI thread. We haven’t yet employed multithreading in any way, but already we have the benefits of running coroutines concurrently!
It’s very easy for us to change this code to run “contributors” coroutines on different threads from the common thread pool. Specify 
Dispatchers.Default
 as the context argument for the 
async
 function:
Copy code
async(Dispatchers.Default) { ... }```
I’m sort of confused. If I don’t specify a dispatcher in the argument for
async
function, isn’t the default dispatcher
Dispatchers.Default
? Yet, I did see the logs change from
Copy code
147 [AWT-EventQueue-0] INFO  Contributors - Clearing result
2251 [AWT-EventQueue-0 @coroutine#1] INFO  Contributors - kotlin: loaded 54 repos
2678 [AWT-EventQueue-0 @coroutine#7] INFO  Contributors - kotlin-benchmarks: loaded 7 contributors
...
to
Copy code
164 [AWT-EventQueue-0] INFO  Contributors - Clearing result
2172 [AWT-EventQueue-0 @coroutine#1] INFO  Contributors - kotlin: loaded 54 repos
2527 [DefaultDispatcher-worker-5 @coroutine#10] INFO  Contributors - anko-example: loaded 2 contributors
2621 [DefaultDispatcher-worker-5 @coroutine#9] INFO  Contributors - kotlinx.html: loaded 15 contributors
...
But when I read the comments in the source code of
Builders.common.kt
, it was stated like this:
Copy code
* 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 [Dispatchers.Default] is used.
 * The parent job is inherited from a [CoroutineScope] as well, but it can also be overridden
 * with corresponding [context] element.
and in
Dispatchers.kt
, it was stated:
Copy code
/**
     * 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. By default, the maximal level of parallelism used
     * by this dispatcher is equal to the number of CPU cores, but is at least two.
     * Level of parallelism X guarantees that no more than X tasks can be executed in this dispatcher in parallel.
     */
    @JvmStatic
    public actual val Default: CoroutineDispatcher = createDefaultDispatcher()
Could someone explain what I’m missing?
j

Joffrey

03/16/2020, 9:48 AM
A dispatcher may already be there in the parent context, so you would inherit it in this case. The default is used only if no dispatcher at all is present I suppose.
You can read a bit about this inheritance of context here: https://medium.com/androiddevelopers/coroutines-first-things-first-e6187bf3bb21
👍 1
d

Dico

03/16/2020, 9:51 AM
The docs you linked look pretty clear to me about the behaviour. Are you familiar with
CoroutineScope
?
j

JP

03/16/2020, 10:47 AM
@Dico No, I just began to learn about coroutines, so I’m not so familiar with it. I just read that suspending functions should be called within
CoroutineScope
or within another suspending function.
j

Joffrey

03/16/2020, 10:48 AM
Copy code
"The default dispatcher for the runBlocking coroutine, in particular, is confined to the invoker thread, so inheriting it has the effect of confining execution to this thread with predictable FIFO scheduling."
https://kotlinlang.org/docs/reference/coroutines/coroutine-context-and-dispatchers.html#unconfined-vs-confined-dispatcher
👍 1
Calling
runBlocking
does provide a Dispatcher that is not the
Default
, that’s why you have to specify
Default
if you want it in child coroutines
j

JP

03/16/2020, 11:13 AM
@Joffrey Oh, I see. So in case of
runBlocking
the default dispatcher is not the
Default
. This I noticed for the first time. I just checked the code once again, and tried to find the parent context. It was not
runBlocking
, but:
main.kt
calls
ContributorsUI
class instance, which implements
Contributors
interface, which again implements
CoroutineScope
interface. The
Contributors
interface has method
loadContributors
which calls the suspending function
loadContributorsConcurrent
, in which the
async
call happens. And I found out inside
Contributors
interface the code:
Copy code
val job: Job

    override val coroutineContext: CoroutineContext
        get() = job + Dispatchers.Main
I guess this code set the parent context’s dispatcher to
Dispatchers.Main
, right? P.S. How should I interpret the expression
job + Dispatchers.Main
? Could someone give a link to read about this? I found in
Jobs.kt
Copy code
public operator fun plus(other: Job) = other
but I think I found the wrong code to read about.
j

Joffrey

03/16/2020, 11:14 AM
I guess this code set the parent context’s dispatcher to
Dispatchers.Main
, right?
It sets this context’s dispatcher to
Main
, and therefore any child coroutine will inherit it by default, unless you specify another one.
j

JP

03/16/2020, 11:15 AM
Yes, that’s what I understood also, thanks to your explanation.
j

Joffrey

03/16/2020, 11:17 AM
How should I interpret the expression
job + Dispatchers.Main
? Could someone give a link to read about this?
CoroutineContext
is a set of elements and using
+
allows to add/combine such elements (like
Job
or
Dispatcher
or
CoroutineName
) to a context. This is explained in the article I linked in my first reply.
j

JP

03/16/2020, 11:18 AM
Thanks a lot again, that helped a lot. 🙂
👍 1
j

Joffrey

03/16/2020, 11:18 AM
It’s basically an example of usage of the
+
operator overloading: https://kotlinlang.org/docs/reference/operator-overloading.html#operator-overloading
j

JP

03/16/2020, 11:23 AM
Yes, that’s why I tried to find the method
plus
in
Jobs.kt
, but I guess it’s the
plus
defined in
CoroutineContext
which is called.
j

Joffrey

03/16/2020, 11:24 AM
Yes, I believe it must be on the
CoroutineContext
type, rather than
Job
, in order to enable combining other kinds of
CoroutineContext
elements
4 Views