Skip to content

Coroutines: Types of dispatchers

Devrath edited this page Jan 13, 2024 · 9 revisions

github-header-image

Quick Reference

Dispatcher Description
Dispatchers.Default Optimized for CPU-intensive work.
Dispatchers.Main Designed for UI-related work.
Dispatchers.IO Optimized for I/O-intensive work (network, database operations).
Dispatchers.Unconfined Does not confine the coroutine to any specific thread.
Custom Dispatcher Create a custom dispatcher based on specific requirements.

Defining dispatchers

  • In Kotlin coroutines, a dispatcher is an essential component that determines the thread or threads on which the coroutine runs.
  • Basically dispatchers help to dispatch the work on a specific thread like UI-thread or background thread
  • Dispatchers are used to specify the execution context for coroutines.
  • Android developers often use coroutines along with dispatchers to handle asynchronous tasks in Android applications. Here are some commonly used dispatchers in Kotlin coroutines for Android:
  1. Default Dispatcher (Dispatchers.Default):

    • This dispatcher is optimized for CPU-intensive work.
    • It is typically used for tasks such as sorting and other CPU-intensive operations.
    • It is backed by a shared pool of threads.
    // Example usage
    GlobalScope.launch(Dispatchers.Default) {
        // Your CPU-intensive work
    }
  2. Main Dispatcher (Dispatchers.Main):

    • This dispatcher is designed for UI-related work.
    • It is the main thread dispatcher and is used for updating the user interface.
    • Use this dispatcher when you need to perform UI-related tasks from a coroutine.
    // Example usage
    GlobalScope.launch(Dispatchers.Main) {
        // UI-related work
    }
  3. IO Dispatcher (Dispatchers.IO):

    • This dispatcher is optimized for I/O-intensive work, such as network or database operations.
    • It uses a pool of threads suitable for I/O tasks.
    • Use this dispatcher when performing tasks like network requests or database operations.
    // Example usage
    GlobalScope.launch(Dispatchers.IO) {
        // I/O-related work
    }
  4. Unconfined Dispatcher (Dispatchers.Unconfined):

    • This dispatcher does not confine the coroutine to any specific thread.
    • The coroutine will resume in whatever thread that is used by the suspending function it is resuming from.
    • Use with caution, as it can lead to unexpected thread switches.
    // Example usage
    GlobalScope.launch(Dispatchers.Unconfined) {
        // Unconfined work
    }
  5. Custom Dispatcher:

    • You can also create custom dispatchers based on your specific requirements.
    • For example, you might create a dispatcher with a fixed thread pool size for a specific type of background task.
    // Example custom dispatcher
    val customDispatcher = newFixedThreadPoolContext(4, "CustomDispatcher")
    
    // Example usage
    GlobalScope.launch(customDispatcher) {
        // Custom dispatcher work
    }

When using coroutines in Android, it's common to use the Dispatchers.Main for UI-related work and Dispatchers.IO for background tasks like network requests. It's important to choose the appropriate dispatcher based on the nature of the task to achieve efficient and responsive application behavior.

Difference between Dispatchers.DEFAULT and Dispatcher.IO

In Kotlin coroutines, Dispatcher.Default and Dispatcher.IO serve different purposes and are designed for different types of tasks. Let's explore the differences between them:

  1. Dispatcher.Default:

    • Optimized for CPU-intensive tasks.
    • Uses a shared pool of threads.
    • Suitable for computationally expensive tasks, such as sorting algorithms or mathematical computations.
    • Not ideal for long-running or blocking I/O operations.
    • Tasks that take a larger number of CPU cycles.
    // Example usage
    GlobalScope.launch(Dispatchers.Default) {
        // CPU-intensive work
    }
  2. Dispatcher.IO:

    • Optimized for I/O-intensive tasks, such as network or database operations.
    • Uses a larger pool of threads compared to Default.
    • Suitable for tasks that involve waiting for external resources, like reading from or writing to a database, making network requests, etc.
    • Ideally used for non-blocking I/O operations.
    • Tasks that are usually waiting.
    // Example usage
    GlobalScope.launch(Dispatchers.IO) {
        // I/O-intensive work
    }

Difference between Dispatchers.Main and Dispatcher.Main.immidiate

The difference is minor and both constructs allow the flow to run on the UI thread but below is the distinction between them

Dispatchers.Main

  • It is similar to Handler(Looper.getLooper()).post(...)
  • Here it adds the UI runnable or task to the message queue, So that only the tasks that are added prior are executed and only then the next task that we add is execute

Dispatchers.Main.immidiate

  • It is similar to Activity.runOnUiThread(...)
  • Here it immediately runs the tasks even though there were earlier tasks that were not yet complete.

Summary

In summary, if you have a task that is mainly CPU-bound or computationally expensive, you might choose Dispatcher.Default. On the other hand, if your task involves I/O operations, such as reading or writing to files, making network requests, or database operations, then Dispatcher.IO is more appropriate.

It's important to select the right dispatcher based on the nature of your coroutine's work to achieve optimal performance and responsiveness in your application. Additionally, consider using Dispatcher.Main for UI-related tasks when updating the user interface from a coroutine.

Clone this wiki locally