美文网首页
Kotlin 协程奇闻录之作用域构建器

Kotlin 协程奇闻录之作用域构建器

作者: 全汪汪 | 来源:发表于2020-04-16 21:09 被阅读0次

奇闻描述

事情是这样的,最近又重新学习协程,毕竟现在协程也相对以前较为完善了。没错他来了,之前每次看到作用域构建器小节都满脸疑惑,也就是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 执行完毕后才输出
        }
    }

懂了吧...直接放了进来之后就很明显了。
其实这已经扯到了挂起函数去了...

相关文章

网友评论

      本文标题:Kotlin 协程奇闻录之作用域构建器

      本文链接:https://www.haomeiwen.com/subject/mmvdvhtx.html