Home > OS >  Kotlin launch vs launch(Dispatchers.Default)
Kotlin launch vs launch(Dispatchers.Default)

Time:11-05

I was testing out how blocking code and coroutines interact for my own understanding. Obviously, we should use non-blocking but I wanted to understand what would happen if there was some blocking code in there.

If I run the following:

fun main() {
    println("Start: ${Thread.currentThread()}")
    runBlocking {
        println("Run Blocking : ${Thread.currentThread()}")
        launch(Dispatchers.D) { // Immediately scheduled for execution
            println("Inside launch: ${Thread.currentThread()}")
        }
        Thread.sleep(10000)
        println("Going to do some other stuff now")
    }
    println("Out of runBlocking")

}

everything runs in the same coroutine and Inside launch: doesn't appear until the Thread.sleep has completed. I assume this is because it is blocking, so no suspending, or use of another coroutine can take place.

If I pass Dispatchers.Default to launch (I thought launch used Dispatchers.Default by default, if you didn't specify one?), the launch block runs in a separate coroutine and starts immediately.

So, why does launch(Dispatchers.Default) allow the second coroutine to start and why doesn't just launch ?

CodePudding user response:

I thought launch used Dispatchers.Default by default, if you didn't specify one

This is where you're mistaken. Here is the documentation:

The coroutine context is inherited from a CoroutineScope. Additional context elements can be specified with context argument. If the context does not have any dispatcher nor any other ContinuationInterceptor, then Dispatchers.Default is used.

This means that if you don't pass a dispatcher to launch, it will default to the dispatcher present in the context of the CoroutineScope in which you started that launch. If the coroutine context doesn't have a dispatcher, then launch will use Dispatchers.Default.

So in your case, a parameterless launch inherits the context and thus the dispatcher provided by runBlocking, which is a single-threaded dispatcher running on the thread that it blocks (the main thread here).

why does launch(Dispatchers.Default) allow the second coroutine to start and why doesn't just launch ?

This is because, as we've just seen, these 2 cases don't involve the same threads. With launch(Dispatchers.Default), the launched coroutine runs on a separate thread pool and can run in parallel of the main one. However, with the parameterless launch, the second coroutine runs on the same thread as the rest of the code, because it runs in the single-threaded dispatcher of runBlocking, which is backed by the main thread.

The last piece of the puzzle is that Thread.sleep is blocking (as you said), unlike delay which is the suspend equivalent from the coroutines library. When there is only one thread involved (in the case of the parameterless launch), running the last Thread.sleep blocks the main thread and never gives a chance to the other coroutine to run. You would need something to suspend execution, for instance delay().

  • Related