Take the following two samples of code (taken from the Kotlin documentation and from the Coroutines library README respectively):
import kotlinx.coroutines.*
fun main() = runBlocking {
launch {
delay(2000)
println("World")
}
println("Hello")
}
In Kotlin >= 1.3.0 one can mark the main()
function as suspend
able and use a coroutineScope
directly.
import kotlinx.coroutines.*
suspend fun main() = coroutineScope {
launch {
delay(2000)
println("World")
}
println("Hello")
}
Both produce the same output:
Hello
World
Are there any functional differences between the two approaches? If yes, what are they?
CodePudding user response:
Your question is pretty unfocused.
runBlocking()
and coroutineScope()
are functionally very similar. They both pause the current execution waiting until the inner coroutine finishes. The difference is that runBlocking()
is meant to be executed from a regular non-suspendable code, so it waits by blocking and coroutineScope()
is used from suspendable context, so it suspends.
That difference makes them do much different things internally. runBlocking()
has to first initialize the whole coroutines machinery before it could execute a suspendable lambda. coroutineScope()
has access to existing coroutine context, so it only schedules the inner lambda to be executed and suspends.
Now, suspend fun main()
is just a "shortcut" that Kotlin compiler provides to make it easier to initialize coroutines apps. Internally, it creates a bridge between the real main function and your suspendable main function. It generates a separate main()
function, which is not suspendable and is the "real" main function. This function initializes a coroutine and uses internal runSuspend()
utility to execute your suspend fun main()
. This is described here: https://github.com/Kotlin/KEEP/blob/master/proposals/enhancing-main-convention.md#implementation-details-on-jvm-1
Both methods of starting a coroutine application are very similar and you can choose according to your taste. One notable difference is that runBlocking()
creates a dispatcher using the current "main" thread. suspend fun main()
also executes using the main thread, but it doesn't specify the dispatcher, so whenever you use e.g. coroutineScope()
it will switch to Dispatchers.Default
. As a result, your runBlocking()
example uses single-threaded dispatcher while your coroutineScope()
example uses multi-threaded Dispatchers.Default
. However, this difference should not really be taken into account when choosing between both methods. We can very easily switch dispatchers at any time.