奇闻描述
事情是这样的,最近又重新学习协程,毕竟现在协程也相对以前较为完善了。没错他来了,之前每次看到作用域构建器小节都满脸疑惑,也就是runningBlock和 coroutineScope的区别。以下是官方的示例:
import kotlinx.coroutines.*
fun main() = runBlocking { // this: CoroutineScope
launch {
delay(200L)
println("Task from runBlocking")
}
coroutineScope { // 创建一个协程作用域
launch {
delay(500L)
println("Task from nested launch")
}
delay(100L)
println("Task from coroutine scope") // 这一行会在内嵌 launch 之前输出
}
println("Coroutine scope is over") // 这一行在内嵌 launch 执行完毕后才输出
}
输出顺序是这样的:
Task from coroutine scope
Task from runBlocking
Task from nested launch
Coroutine scope is over
但是程序没有运行之前,我感觉顺序是这样的:
Coroutine scope is over
Task from coroutine scope
Task from runBlocking
Task from nested launch
放到最外层runBlocking的代码应该先运行才对的,因为官方都说了嘛,协程是不堵塞线程的,所以runBlocking应该不会堵塞,直接运行其最外围代码才对。
于是我看了下官方的解释:
runBlocking方法会阻塞当前线程来等待, 而 coroutineScope只是挂起,会释放底层线程用于其他用途。 由于存在这点差异,runBlocking是常规函数,coroutineScope而是挂起函数。
我寻思啥是挂起函数啊,话说挂起函数最直观的不就是suspend修饰符的方法吗,这有什么关系。
然后点开coroutineScope源码:
public suspend fun <R> coroutineScope(block: suspend CoroutineScope.() -> R): R =
suspendCoroutineUninterceptedOrReturn { uCont ->
val coroutine = ScopeCoroutine(uCont.context, uCont)
coroutine.startUndispatchedOrReturn(coroutine, block)
}
行吧,原来你是个挂起函数,suspend 修饰符。
但我依旧有点懵逼,还是没清楚是怎么回事。
于是我尝试用自己写的挂起函数来代替:
fun corKx() {
runBlocking {
launch {
delay(200L)
println("Task from runBlocking")
}
Ktcomputer()
println("Coroutine scope is over") // 这一行在内嵌 launch 执行完毕后才输出
}
}
//自己写的代替coroutineScope的挂起函数,削减了一个子协程,因为这里只是探讨coroutineScope
suspend fun Ktcomputer(){
delay(500L)
println("Task from nested launch")
}
然后结果是:
Task from runBlocking
Task from nested launch
Coroutine scope is over
懂了吗?
嗯...没懂,这么说吧为什么要定义挂起函数,是因为我要需要在函数里要用到挂起函数。
所以上面实际上可以把自己定义的挂起函数内容直接放到runBlocking里也就是这样:
fun corKx() {
runBlocking {
launch {
delay(200L)
println("Task from runBlocking")
}
delay(500L)
println("Task from nested launch")
println("Coroutine scope is over") // 这一行在内嵌 launch 执行完毕后才输出
}
}
懂了吧...直接放了进来之后就很明显了。
其实这已经扯到了挂起函数去了...
网友评论