71

In this question: Kotlin Coroutines choosing Dispatcher we can understand to use Dispatcher.Default on CPU process, like an image/video conversion and Dispatcher.IO when writing/reading files or API connection.

But in the class Dispatcher.kt documentation, for the IOyou find this:

* This dispatcher shares threads with a [Default][Dispatchers.Default] dispatcher, so using
* `withContext(Dispatchers.IO) { ... }` does not lead to an actual switching to another thread —
* typically execution continues in the same thread.

So basically they run on the same thread anyway. There is a real difference or in the end it won't matter each one to use?

Thanks!

Canato
  • 3,598
  • 5
  • 33
  • 57

2 Answers2

127

The difference is that Dispatchers.Default is limited to the number of CPU cores (with a minimum of 2) so only N (where N == cpu cores) tasks can run in parallel in this dispatcher.

On the IO dispatcher there are by default 64 threads, so there could be up to 64 parallel tasks running on that dispatcher.

The idea is that the IO dispatcher spends a lot of time waiting (IO blocked), while the Default dispatcher is intended for CPU intensive tasks, where there is little or no sleep.

Francesc
  • 25,014
  • 10
  • 66
  • 84
  • 19
    It should be noted that `Dispatchers.Default` exists because if your coroutines are CPU bound then running them on more threads than you have cores just wastes time on context switching and thread overhead, but you still need more threads than cores if you're doing blocking IO, hence `Dispatchers.IO`. – Jesse Jan 25 '21 at 09:42
  • Would you use "Default" or "IO" in case you just perform some query with the DB (no network) ? – android developer May 11 '21 at 11:21
  • 3
    Database query is an IO operation, so it should use the IO dispatcher. – Francesc May 11 '21 at 15:34
  • @Jesse So Dispatchers.Default is optimized for CPU intensive works just because there is no context swithces, right? IO and Default share same threads. Did i get i right? Or Dispatchers.Default is optimized for CPU intensive works because CoroutineScheduler allocates more cycles for Default than IO? – Teyyihan Aksu May 11 '21 at 21:13
  • 2
    @TeyyihanAksu `Dispatchers.IO` and `Dispatchers.Default` do share the same thread pool so that switching between them doesn't require switching threads, but that is just an optimization. Conceptually you can think of them as different thread pools. One with a thread for each CPU core (`Dispatchers.Default`), and the other with `kotlinx.coroutines.io.parallelism` as the number of threads (`Dispatchers.IO`). – Jesse May 12 '21 at 05:38
  • @Francesc all network and database operations are write-read operations, which means that they're input-output operations and therefore should only be ran on Dispatchers.IO – M.Ed Jun 28 '22 at 08:41
  • So I assume those 64 threads are in a thread pool (named something like IO-threadpool for example). And where can I see the configuration of this default threadpool provided by Kotlin, like executor used and the corePoolSize maxPoolSize queueCapacity etc values – firstpostcommenter May 21 '23 at 16:44
  • If you are comparing this "so only N (where N == cpu cores) tasks can run in parallel in this dispatcher" and this "IO dispatcher there are by default 64 threads, so there could be up to 64 parallel tasks running on that dispatcher." does that mean that cpu cores are threads and threads are cpu cores? – Red M Jul 13 '23 at 19:34
  • ARM does not use hyperthreading or equivalent, so 1 CPU core == 1 thread. – Francesc Jul 13 '23 at 21:20
52

So basically they run on the same thread anyway. There is a real difference or in the end it won't matter each one to use?

Your quote from the documentation just details an optimization Kotlin introduced: when switching contexts between Default and IO, you don't pay for the expensive handoff to another thread; instead the thread itself moves to the other pool.

This doesn't affect the overall properties of the thread pools behind the Default and IO dispatchers:

  • Default has a fixed size hardcoded to the number of available processors, because that's what makes sense for CPU-intensive tasks.
  • IO is an elastic thread pool with a configurable max size. Threads in this pool are expected to spend most of their time in a non-runnable state, awaiting the completion of an IO operation, so it makes sense to have more of them than there are CPU cores.
Marko Topolnik
  • 195,646
  • 29
  • 319
  • 436
  • 2
    Could you provide more information about "instead the thread itself moves to the other pool". Thank you :) – Kiwi Lin Jan 29 '21 at 01:44
  • 3
    Thread belonging to a pool is a matter of bookkeeping. If you move a `Thread` object from IO's thread list to Default's thread list, you have moved a thread to the other pool. – Marko Topolnik Jan 29 '21 at 13:07
  • that "instead the thread itself moves to the other pool" caught my eye too - @MarkoTopolnik you mean that thread is moved during runtime from one pool to another? By whom? – Marian Paździoch Apr 25 '22 at 07:28
  • @MarianPaździoch Yes, I guess that's what happens. By whom -- by the internals of the dispatcher implementation. – Marko Topolnik Apr 25 '22 at 08:24