I am quite new to coroutines and I don't seem to u...
# coroutines
t
I am quite new to coroutines and I don't seem to understand some basic examples:
Copy code
fun main() = runBlocking {
//sampleStart
    launch {
        repeat(1000) { i ->
            println("I'm sleeping $i ...")
            delay(500L)
        }
    }
    delay(1300L) // just quit after delay
//sampleEnd    
}
Prints 3 lines and exits because it uses a daemon thread
Copy code
I'm sleeping 0 ...
I'm sleeping 1 ...
I'm sleeping 2 ...
But main waits for
coroutineScope
to finish execution
Copy code
fun main() = runBlocking { // this: CoroutineScope
    launch { 
        delay(200L)
        println("Task from runBlocking")
    }

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

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

    println("Coroutine scope is over") // This line is not printed until nested launch completes
}
And prints this
Copy code
Task from coroutine scope
Task from runBlocking
Task from nested launch
Coroutine scope is over
Is there a magic done by
coroutineScope
that makes it block the main from finishing? Any help is appreciated.
m
The first example will print all numbers if you wait long enough. I got this when I reduced the repeat to 5 times:
Copy code
I'm sleeping 0 ...
I'm sleeping 1 ...
I'm sleeping 2 ...
I'm sleeping 3 ...
I'm sleeping 4 ...
The
coroutineScope
will wait for all child-coroutines to complete before the scope completes. The
runBlocking
function also creates a coroutinescope that will behave that way.
💯 1
r
coroutineScope { ... }
is akin to
runBlocking { ... }
, with the difference that it suspends and not blocks. There are of course subtle differences under the hood as
runBlocking
sets up the bridge between blocking and non-blocking worlds in the absence of external event loop (and that's the only legitimate use case for this function), but you can skip that for the time being.
💯 1
t
Marius and Andrew thanks for the quick response
So to my understanding now, it seems
runBlocking
waits for
coroutineScope
to finish executing its nested coroutines but doesn't wait for coroutines like
launch
to finish execution, is that right?
m
It waits for
launch
too.
Unless you call
launch
on another scope.
t
I edited the first example to this:
Copy code
fun main() = runBlocking {
    //sampleStart
    coroutineScope{
        launch {
            repeat(20) { i ->
                println("I'm sleeping $i ...")
                delay(500L)
            }
        }
    }

    println("Finished with launch blocking")
    delay(1300L) // just quit after delay
    println("Exiting main")
//sampleEnd
}
It printed the whole 20 "I am sleeping" before exiting, But without wrapping the
repeat
in
coroutineScope
, it stoped at the third loop
Marius thanks I understand it now
m
That doesn't happen here if I remove the
coroutineScope
. I think you just need to wait longer.
t
Yes that is true, but if you wrap the repeat in
coroutineScope
, "Exiting main" will be the last line to be printed. In your example without
coroutineScope
, it "Exiting main" is printed on the 6th line
So can I conclude that
coroutineScope
doesn't allow
runBlocking
to execute next line until it finishes but
launch
does allow it ?
m
coroutineScope
will only wait for child-coroutines when the scope exists (at the
}
). It does not have anything to do with
launch
running asynchronously.
So when you added the
coroutineScope
around
launch
, it was just waiting for
launch
to finish.
t
Okay I see 🙂. Thanks.