kotlinkotlin-coroutines

Why does the Kotlin coroutine output "A B" even with a delay?


I have the following Kotlin code snippets using coroutines, and I'm puzzled by the output. Can someone explain why the output is "A B" in both cases?

// Code Snippet 1
fun main() {
  CoroutineScope(Dispatchers.IO).launch { 
        print("A")
    }
    print("B")
}

output: AB

// Code Snippet 2
fun main() {
    CoroutineScope(Dispatchers.IO).launch { 
        delay(200)
        print("A")
    }
    print("B")
}

output AB

i have ran this code on kotlin playground ( link - kotlin playground I am not able to understand why A prints before B even after adding a delay of 200ms


Solution

  • Interesting. I would expect at least the second case to only print B, because the program terminates before A gets the chance to be printed. This is actually what I get when running your code in the IDE.

    Your playground link uses println, not print, and yet prints this weird A B output on the same line. This might be a bug in the Kotlin playground's stdout handling when outputting from different threads. Don't trust concurrent output from the playground I suppose.

    EDIT: I confirm, the payload received by the playground contains "text": "A\n<outStream>B\n</outStream>", which seems to explain the bad display of concurrent output (only the main thread's output is wrapped in <outStream> here).

    This bug aside, you should note that you don't wait for the coroutine you launch in any way here. This means that any execution order is technically possible: the main body can print B before or after the launched coroutine executes, and the program can even terminate before the launched coroutine executes or finishes.

    You could use Thread.sleep() at the end to block the main thread while waiting for the other coroutine to complete, but that's not idiomatic with coroutines.

    If you want to automatically wait for the coroutine to complete, you should use structured concurrency (for instance use a runBlocking or a suspend fun main()+coroutineScope here):

    fun main(): Unit = runBlocking {
        launch(Dispatchers.IO) {
            delay(200)
            println("A")
        }
        println("B")
    }
    

    runBlocking will automatically wait for child coroutines to finish before returning, so your main thread will be blocked waiting for A to be printed, which will prevent the program from terminating too early.