先來(lái)看下官網(wǎng)的表述:
In addition to the coroutine scope provided by different builders, it is possible to declare your own scope using coroutineScope builder. It creates a coroutine scope and does not complete until all launched children complete. The main difference between runBlocking and coroutineScope is that the latter does not block the current thread while waiting for all children to complete.
import kotlinx.coroutines.*
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
}
上面的這段描述很簡(jiǎn)單,但是,執(zhí)行完上面的代碼后,就有點(diǎn)小迷惑了,按照官方的說(shuō)法,coroutineScope是不會(huì)阻塞當(dāng)前線程的,那么Coroutine scope is over 應(yīng)該在coroutineScope代碼段執(zhí)行之前打印才對(duì)啊,為什么每次執(zhí)行的結(jié)果都是最后才打印Coroutine scope is over?
if (你清楚的直到其中的原理) {
return
}
其實(shí),我看完之后,產(chǎn)生迷惑的原因主要是因?yàn)楣俜侥?code>runBlocking和coroutineScope來(lái)比較,給出的例子也不直觀。但是其實(shí)他們倆完全是不同的東西。讓我們自己重新?lián)Q個(gè)例子再來(lái)理解下:
1. runBlocking
Runs a new coroutine and blocks the current thread interruptibly until its completion
fun main() {
runBlocking {
Log.i("CoroutineDemo", "before delay in coroutine")
delay(500L)
Log.i("CoroutineDemo", "after delay in coroutine")
}
Log.i("CoroutineDemo", "out coroutine")
}
這里用runBlocking創(chuàng)建來(lái)一個(gè)協(xié)程并立即執(zhí)行,按照runBlocking簽名上的注釋來(lái)說(shuō),runBlocking會(huì)阻塞當(dāng)前線程,所以,我們?cè)趨f(xié)程里用delay來(lái)掛起協(xié)程,看看打印結(jié)果:
CoroutineDemo: before delay in coroutine
CoroutineDemo: after delay in coroutine
CoroutineDemo: out coroutine
很顯然,runBlocking確實(shí)阻塞了當(dāng)前線程。
2. coroutineScope
Creates a [CoroutineScope] and calls the specified suspend block with this scope.
coroutineScope只是一個(gè)suspend function,它和runBlocing有本質(zhì)的區(qū)別。
fun main() {
GlobalScope.launch(start = CoroutineStart.UNDISPATCHED) {
coroutineScope {
Log.i("CoroutineDemo", "before delay in coroutine")
delay(500L)
Log.i("CoroutineDemo", "after delay in coroutine")
}
}
Log.i("CoroutineDemo", "out coroutine")
}
這里我們用GlobalScope來(lái)創(chuàng)建一個(gè)頂級(jí)的協(xié)程,并設(shè)置start參數(shù)為UNDISPATCHED,立即執(zhí)行。
來(lái)直接看執(zhí)行結(jié)果:
CoroutineDemo: before delay in coroutine
CoroutineDemo: out coroutine
CoroutineDemo: after delay in coroutine
很顯然,coroutineScope在執(zhí)行完delay掛起之前的代碼后,就立即將控制權(quán)交給了所在的線程,線程并沒(méi)有被阻塞,并立即去執(zhí)行協(xié)程外面的事情去了。最后掛起時(shí)間到了后,才又將控制權(quán)交回協(xié)程,繼續(xù)執(zhí)行delay后面的代碼。
由上面兩個(gè)例子可見(jiàn),runBlocking和coroutineScope除了有本質(zhì)的區(qū)別外,最大的不同就在于兩者所在的協(xié)程被掛起后對(duì)所在線程的影響,runBlocking所在協(xié)程被掛起后會(huì)阻塞所在線程,線程不能處理協(xié)程之外的事情;coroutineScope所在的協(xié)程被掛起后,則會(huì)立即交出控制權(quán)給所在的線程,不會(huì)阻塞線程,線程可以處理協(xié)程之外的事情。
相關(guān)的解釋請(qǐng)參考:
Coroutines: runBlocking vs coroutineScope
最后幫朋友打個(gè)小廣告