Deep Dive into Dispatchers for Kotlin Coroutines
Learn what Dispatchers are, their types, specifics of Unconfined Dispatchers and main difference between IO and Default dispatchers.
What are Dispatchers in Kotlin Coroutines?
Types of Dispatchers
There are basically four types of Dispatchers:
- Dispatchers.Main: A coroutine dispatcher that is confined to the Main thread operating with UI objects. Usually such dispatcher is single-threaded.
- Dispatchers.Default: The default CoroutineDispatcher that is used by all standard builders like launch, async, etc. if no dispatcher nor any other ContinuationInterceptor is specified in their context.
- Dispatchers.IO: The CoroutineDispatcher that is designed for offloading blocking IO tasks to a shared pool of threads.
- Dispatchers.Unconfined: A coroutine dispatcher that is not confined to any specific thread. It executes initial continuation of the coroutine in the current call-frame and lets the coroutine resume in whatever thread that is used by the corresponding suspending function, without mandating any specific threading policy.
Looks like definitions are too theoretical and confusing! Don’t worry, examples make every line of definition above clear!
Case 1: Don’t specify the dispatcher:
If you run above, you get:
Current thread is: main
Because, When launch { ... }
is used without parameters, it inherits the context (and thus dispatcher) from the CoroutineScope it is being launched from. In this case, it inherits the context of the main runBlocking
coroutine which runs in the main
thread.
Case 2: Specify the default dispatcher:
If you run above, you get:
Current thread is: DefaultDispatcher-worker-1
Case 3: Specify the IO dispatcher:
If you run above, you get:
Current thread is: DefaultDispatcher-worker-1
Case 4: Specify Unconfined Dispatcher:
If you run above, you get:
Current thread is: main
Looks like Dispatchers.Unconfined is a special dispatcher that also appears to run in the main
thread, but that’s not true.
It starts a coroutine in the caller thread, but only until the first suspension point. There was no suspension point in above code, so it started in the caller (main) thread. But what if there is a suspension point like below:
If you run above, you get:
Current thread is: main
Current thread after delay is: kotlinx.coroutines.DefaultExecutor
So, from above output, now its definition is clear:
Would you like to guess output of below?
Current thread is: main
Current thread after delay is: main
Here, it inherits the context of the main runBlocking
coroutine which runs in the main
thread, both before and after the delay.
Difference between IO and Default Dispatcher
The main difference between these two is as below:
Default Dispatcher (preferred for operations you want to off-load from the main thread like CPU-intensive operations):
IO Dispatcher (preferred for heavy IO operations like read/write files, uploading or decrypting/encrypting files):
If you define:
// 100 threads for MySQL connection
val myMysqlDbDispatcher = Dispatchers.IO.limitedParallelism(100)
// 60 threads for MongoDB connection
val myMongoDbDispatcher = Dispatchers.IO.limitedParallelism(60)
Conclusion:
So you learnt role & types of dispatchers, specifics of Unconfined Dispatchers and difference between IO and default dispatchers.
Hope you enjoyed reading it, if yes, please leave a clap that’s my motivation and don’t forget to follow me for notifications on my future posts.
Happy coding till then :)
References:
1. https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines/-dispatchers/index.html
2. https://github.com/Kotlin/kotlinx.coroutines/blob/master/kotlinx-coroutines-core/jvm/src/Dispatchers.kt