question-mark
Stuck on an issue?

Lightrun Answers was designed to reduce the constant googling that comes with debugging 3rd party libraries. It collects links to all the places you might be looking at while hunting down a tough bug.

And, if you’re still stuck at the end, we’re happy to hop on a call to see how we can help out.

`DefaultDispatcher` - why is this the CommonPool?

See original GitHub issue

RxJava is synchronous by default. This behavior is awesome.

observable.subscribe { }

By default, coroutine builders like launch, async, produce, etc use the CommonPool. In RxJava, that’s like automatically doing:

observable.subscribeOn(Schedulers.computation()).subscribe { }

Because it’s a good pattern for testing and maintainability, I always inject my dispatchers.

launch(dispatchers.background) { }

Unfortunately, the DefaultDispatcher lets unfamiliar devs easily make the mistake of referring to the common pool. Even worse, they may not even understand what the CommonPool is and just throw coroutines around and not understand in which dispatcher they run in.

launch { } // surprise! runs in the common pool

Why not make the default dispatcher Unconfined? That way devs will know that if they want to confine the coroutine to a particular context, they can pass the appropriate dispatcher.

I think it’s a bit confusing to have different coroutine builders refer to different dispatchers.

Note: I understand it’s probably too late to change this behavior 😦

Issue Analytics

  • State:closed
  • Created 5 years ago
  • Comments:14 (9 by maintainers)

github_iconTop GitHub Comments

6reactions
jcornazcommented, May 7, 2018

This is quite opinionated I think. In my opinion, Unconfined would have been indeed a good default, for the reasons you mentioned. However, if it is better than CommonPool I am less sure.

if launch and async would be unconfined by default, then someone would have writen a similar post to yours with the following snippet:

async { } // surprise! It is not asynchronous!

Usually if you use async or launch, this is because you want to launch a concurrent coroutine (that’s why it is named like this). So it does make sense to use CommonPool by default IMO.

And I’d like to precise that subscribe of RxJava should not be compared to launch or async, it has to be compared to its equivalent for coroutines: consumeEach:

observable.subscribe { } // sychronous? asynchronous? Who knows? You have to check if `subscribeOn` and/or `observeOn` is present in the upstream.
channel.consumeEach { } // This is a suspending function always executed synchronously in the current context.
4reactions
elizarovcommented, Sep 12, 2018

We’ve lived with “you must be explicit” for a while, but we had to abandon this policy when we started to work on common code. You cannot require to be explicit in your common code, since JVM has threads and pool, but JS does no, so you cannot just go a write code that runs both on JS and JVM. We needed some default.

What that default should be? It cannot be Unconfined for the reasons outlined above (asynchronous code ceases to be asynchronous). Moreover, in JS world it is natural to always dispatch your tasks on your event thread (unconfined is not idiomatic in JS). The best analogue of “the event thread” that we have for JVM is the pool of threads sized to the number of CPU cores, hence it is our default.

Now, with structured concurrency (#410) this should not be a big issue anymore. A default is used only when you do GlobalScope.launch, which should not be done often (and should never be done in larger projects), so we are kind of back to requiring explicit dispatcher. Now in you apps you need to define your own CoroutineScope where you have to define which dispatcher works best for you.

Read more comments on GitHub >

github_iconTop Results From Across the Web

CommonPool default for coroutines
coroutines have implemented their own thread pool a while ago (available under the Dispatchers.Default dispatcher) and they are doing a semi-FIFO scheduling.
Read more >
Why does IO Dispatchers create more than 64 thread in ...
Max thread rented from CommonPool by Dispatchers.IO is 64. Dispatchers.Default can still create more threads, if all 64 is busy by ...
Read more >
Demystifying Kotlin Coroutines
launch takes CoroutineContext as first parameter which then defaults to DefaultDispatcher which is a CommonPool class which creates a ...
Read more >
CommonPool - kotlinx-coroutines-core
Represents common pool of shared threads as coroutine dispatcher for compute-intensive tasks. If there isn't a SecurityManager present it uses ...
Read more >
Kotlin Android Coroutine Context: Default Dispatcher vs ...
When you use launch or async without any arguments, it actually uses DefaultDispatcher. DefaultDispatcher: It is currently equal to CommonPool, ...
Read more >

github_iconTop Related Medium Post

No results found

github_iconTop Related StackOverflow Question

No results found

github_iconTroubleshoot Live Code

Lightrun enables developers to add logs, metrics and snapshots to live code - no restarts or redeploys required.
Start Free

github_iconTop Related Reddit Thread

No results found

github_iconTop Related Hackernoon Post

No results found

github_iconTop Related Tweet

No results found

github_iconTop Related Dev.to Post

No results found

github_iconTop Related Hashnode Post

No results found