Home > OS >  Kotlin Coroutines Dispatchers.IO is not creating expected threads
Kotlin Coroutines Dispatchers.IO is not creating expected threads

Time:09-04

I was just checking the behaviour of the Coroutine Dispatchers. So I was trying to understand how many threads each of these Dispatchers can create. To check this, I created a loop statement counting from 1 to 1_000_000.

In each loop iteration, I'm creating a coroutine with Dispatchers.IO, But when I see the output, it is not created 1_000_000 coroutines, and all these are DefaultDispatcher-worker threads, and it always stops execution in the range 40000-50000 randomly.

But when I replaced Dispatchers.IO with Dispatchers.Unconfined, it actually created all the 1_000_000 coroutines without fail and all these are created on Main thread.

So I need some help here to understand why Dispatchers.IO is failed in this case.

Dispatchers.IO:

fun main() {
    println("Start of main")

    val handler = CoroutineExceptionHandler { _, e -> e.printStackTrace() }

    runBlocking {
        for (i in 1..1000000) {
            CoroutineScope(Dispatchers.IO   CoroutineName("Dispatchers.IO")).launch(handler) {
                println("${Thread.currentThread().name}  task number is :$i")
            }
        }
    }
    println("End of main")
}

Dispatchers.Unconfined

fun main() {
    println("Start of main")

    val handler = CoroutineExceptionHandler { _, e ->
        e.printStackTrace()
    }

    runBlocking {
        for (i in 1..1000000) {
            CoroutineScope(Dispatchers.Unconfined   CoroutineName("Dispatchers.Unconfined")).launch(handler) {
                println("${Thread.currentThread().name}  task number is :$i")
            }
        }
    }
    println("End of main")
}

Thanks in advance

CodePudding user response:

But when I see the output, it is not created 1_000_000 coroutines, and all these are DefaultDispatcher-worker threads, and it always stops execution in the range 40000-50000 randomly.

The reason for this, I believe is that you're not waiting for all child coroutines to complete, and your program exits prematurely.

In the below code, Job instances are collected in a list named jobs. After the loop, jobs.joinAll() causes the execution to wait for all child coroutines to complete.

What is interesting, is the difference in execution time Dispatchers.IO vs. Dispatchers.Unconfined.

  • Dispatchers.IO: Elapsed time 4.040274590s
  • Dispatchers.Unconfined: Elapsed time 959.173375ms

When adding the suspending delay(1) to the loop, Dispatchers.Unconfined will change thread from main to kotlinx.coroutines.DefaultExecutor.

Dispatchers.Unconfined executes in strict sequence 1..1_000_000.

Coroutines basics

Tested on AMD 8-core, Ubuntu 20.04.

import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.Job
import kotlinx.coroutines.joinAll
import kotlinx.coroutines.launch
import kotlinx.coroutines.runBlocking
import kotlin.time.ExperimentalTime
import kotlin.time.measureTime

@OptIn(ExperimentalTime::class)
fun main() {

    println("Start of main")

    measureTime {
        runBlocking {

            val jobs = mutableListOf<Job>()

            repeat(1_000_000) { index ->
                jobs.add(launch(Dispatchers.IO) {
                    println("${Thread.currentThread().name}  task number is :${index   1}")
                })
            }

            /** wait until child coroutines complete */
            jobs.joinAll()

            println("End of main")
        }
    }.also { duration -> println("Elapsed time: $duration") }
}
  • Related