What are dispatchers in Kotlin coroutines?

Abhishek Srivastava
3 min readApr 14, 2023

What are dispatchers?

A dispatcher is an essential functionality provided by Kotlin coroutines. It helps us to conclude which coroutine will run on which thread from a pool of threads.

Types of dispatchers

There are four types of dispatchers depending on the work we want the coroutine to do.

  1. Default dispatcher
  2. Main dispatcher
  3. IO dispatcher
  4. Unconfined dispatcher

Default dispatcher

We use the default dispatcher when we want to run CPU-intensive functions. If we forget to choose our dispatcher, this dispatcher will be selected by default.

We should use Dispatchers.Default to perform CPU-intensive tasks.

Example use cases:

  • Doing heavy calculations like Matrix multiplications.
  • Doing any operations on a bigger list present in the memory like sorting, filtering, searching, etc.
  • Applying the filter on the Bitmap present in the memory, NOT by reading the image file present on the disk.
  • Parsing the JSON available in the memory, NOT by reading the JSON file present on the disk.
  • Scaling the bitmap already present in the memory, NOT by reading the image file present on the disk.
  • Any operations on the bitmap that are already present in the memory, NOT by reading the image file present on the disk.

Syntax

launch(Dispatchers.Default)

Main dispatcher

It is not used very often. It’s only used in Android applications when we want to interact with the UI. It is restricted to the main thread as it is only used when we want to run our coroutine on the main thread. If we’re going to use this, we first need to set a dispatcher using Dispatchers.setMain(dispatcher).

Example use cases:

  • Performing UI-related tasks.
  • Any small tasks like any operations on a smaller list present in the memory like sorting, filtering, searching, etc.

Syntax

launch(Dispatchers.Main)

IO dispatcher

It is used when we want to block threads with I/O (input-output) operations, such as when we want to read/write files.

We should use Dispatchers.IO to perform disk or network I/O-related tasks. In a nutshell, anything related to file systems or networking should be done using Dispatchers.IO as those tasks are IO-related tasks.

We can think of Dispatchers.IO as a Schedulers.io() of RxJava.

Example use cases:

  • Any network operations like making a network call.
  • Downloading a file from the server.
  • Moving a file from one location to another on disk.
  • Reading from a file.
  • Writing to a file.
  • Making a database query.
  • Loading the Shared Preferences.

Syntax

launch(Dispatchers.IO)

Unconfined dispatcher

An unconfined dispatcher isn’t restricted to a particular thread. This dispatcher contrasts with those mentioned earlier as it changes no threads. At the point when it is begun, it runs on the thread on which it was begun.

Syntax

launch(Dispatchers.Unconfined)

Confined vs. Unconfined Dispatchers

By default, a dispatcher is inherited from outer CoroutineScope unless we explicitly pass a dispatcher to builder functions:

runBlocking(Executors.newSingleThreadExecutor().asCoroutineDispatcher()) {
launch {
Assertions.assertTrue(
coroutineContext[ContinuationInterceptor]!!
.javaClass
.name.contains("ExecutorCoroutineDispatcher")
)
Assertions.assertTrue(Thread.currentThread().name.startsWith("pool"))
}
}

On the other hand, Dispatchers.Unconfined references the internal object Unconfined, which overrides the CoroutineDispatcher#isDispatchNeeded with false:

override fun isDispatchNeeded(context: CoroutineContext): Boolean = false

It causes the coroutine to start in the caller thread until the coroutine calls a suspend block, then resumes the suspending function’s thread:

runBlocking {
launch(Dispatchers.Unconfined) {
Assertions.assertTrue(Thread.currentThread().name.startsWith("main"))
delay(10)
Assertions.assertTrue(!Thread.currentThread().name.startsWith("main"))
}
}

Coroutines that are not CPU intensive and don’t update any shared data are appropriate for Dispatchers#Unconfined.

Explanation

  • Line 1: Wrap a suspending main body using coroutineScope.
  • Line 3: Start a coroutine on Dispatcher.Default.
  • Line 4: Start a coroutine on Dispatcher.Unconfined.
  • Line 5: Start a coroutine on Dispatcher.IO.

Original The Educative Team from https://www.educative.io/answers/what-are-dispatchers-in-kotlin-coroutines

--

--

Abhishek Srivastava

Senior Software Engineer | Android | Java | Kotlin | Xamarin Native Android | Flutter | Go