Vikas Acharya
Vikas Acharya

Reputation: 4152

how coroutine scope builder flow works

Kotlin says

fun main() = runBlocking { // this: CoroutineScope
    launch { 
        delay(200L)
        println("Task from runBlocking")
    }

    coroutineScope { // Creates a coroutine scope
        launch {
            delay(500L) 
            println("Task from nested launch")
        }

        delay(100L)
        println("Task from coroutine scope") // This line will be printed before the nested launch
    }

    println("Coroutine scope is over") // This line is not printed until the nested launch completes
}

in above example what i expect is :-

This is what my understanding on runBlocking and coroutineScope. Which is not working as expected.

the Output is

Task from coroutine scope
Task from runBlocking
Task from nested launch
Coroutine scope is over

Can anyone kindly explain in a easy way to understand this.

Upvotes: 4

Views: 2085

Answers (2)

Vikas Acharya
Vikas Acharya

Reputation: 4152

I modified the code a little

fun main() = runBlocking(Dispatchers.Default) {

    var i = 1
    launch {
        println("Task from runBlocking")
        while (i < 10) {
            delay(30L)
            println(i++)
        }
    }

    coroutineScope { // Creates a coroutine scope
        launch {
            delay(200L)
            println("Task from nested launch")
        }

        delay(100L)
        println("Task from coroutine scope") // This line will be printed before the nested launch
    }

    println("Coroutine scope is over")

}

Output

Task from runBlocking
1
2
3
Task from coroutine scope
4
5
6
Task from nested launch
Coroutine scope is over
7
8
9

the observation i made is,

  • delay(100L) is equal to approximate 3 times delay(30L)

  • delay(200L) is equal to approximate 6 times delay(30L)

So, after 3 Task from coroutine scope and after 6 Task from nested launch is printed.

then exactly after this Coroutine scope is over but you can still see the loop printed 7,8,9.

This is because like runBlocking coroutineScope waits for all its members to execute by suspending underlying threads. But understand, those threads first work on members of coroutineScope not on runBlocking.

Hence, it is printing Task from coroutine scope and Task from nested launch before Coroutine scope is over

Upvotes: 2

Haim
Haim

Reputation: 560

launch causes the block to be executed asynchronously, so the call to launch returns immediately, and the coroutine continues its running and doesn't wait for the execution of the launched block.

Therefore, immediately after runBlocking is called, the first and the second launch are called one after another, and immediately after that the coroutine is suspended on delay(100L).

After 100ms the coroutine is resumed and prints "Task from coroutine scope", and then the execution of the nested coroutine-scope's block ends. A coroutine-scope always waits for the end of execution of all the jobs it has launched, so it waits here for 500ms.

Meanwhile, the two launched blocks are executed, so "Task from runBlocking" is printed first (after 200ms from the start), and then "Task from nested launch" is printed (after 500ms from the start).

Eventually, after the internal launched job has been completed, the internal coroutine-scope finishes waiting, and the external coroutine continues and prints "Coroutine scope is over".

This is the story. I hope it helps a little to understand how the code is executed and why the order of printing is like that.

Upvotes: 6

Related Questions