美文网首页Kotlin
kotlin协程--coroutineScope函数

kotlin协程--coroutineScope函数

作者: 最爱大头猫 | 来源:发表于2021-11-22 13:42 被阅读0次

    public suspend fun <R> coroutineScope(block: suspend CoroutineScope.() -> R): R {
        contract {
            callsInPlace(block, InvocationKind.EXACTLY_ONCE)
        }
        return suspendCoroutineUninterceptedOrReturn { uCont ->
            val coroutine = ScopeCoroutine(uCont.context, uCont, true)
            coroutine.startUndispatchedOrReturn(coroutine, block)
        }
    }
    

    它是一个suspend函数创建一个新的协程作用域,并在该作用域内执行指定代码块,它并不启动协程。其存在的目的是进行符合结构化并发的并行分解(即,将长耗时任务拆分为并发的多个短耗时任务,并等待所有并发任务完成后再返回)。

    coroutineScoperunBlocking的区别在于runBlocking会阻塞当前线程,而coroutineScope会挂起所在的协程直至其内部任务(包括子协程)执行完成,它不会阻塞所在的线程。

    coroutineScope是一个挂起函数,它被挂起后,会转而执行之前的子协程

    fun main() = runBlocking {
        launch {        //launch①       
            delay(1000)                 //挂起launch①
            println("test2")
        }
        println("test1")
        coroutineScope {                //第一次挂起runBlocking,直至内部逻辑完成
            launch {    //launch②
                delay(2000)             //挂起launch②
                println("test3")
            }
            delay(5000)     //delay①    //第二次挂起runBlocking
            println("test4")
        }
        println("test5")
    }
    //test1
    //test2
    //test3
    //test4
    //test5
    

    上述代码分析:

    1. runBlockingmain线程创建并启动一个阻塞的协程;
    2. 创建launch①子协程,由于创建协程是需要一些时间的,并且协程的创建是由特定的线程来完成,并非是main线程。所以在创建协程过程中会并行地执行后续代码。因此test1被输出。
    3. 执行到coroutineScope函数时,把runBlocking挂起,直到内部逻辑执行完成。
    4. 然后创建launch②协程,创建过程中执行执行后续代码:delay①继续挂起runBlocking5s(挂起函数中调用挂起函数)。
    5. 等到launch①创建完毕时,把它挂起1s。launch②创建完毕时,把它挂起2s。
    6. 此时runBlocking、launch①、launch②都是被挂起状态。
    7. 等到1s后launch①恢复,输出test2;2s后launch②被恢复,输出test3;5s后runBlocking第二次挂起被恢复,输出test4
    8. 此时coroutineScope中的逻辑已经执行完成,恢复runBlocking的第一次挂起,test5被输出。

    这比较难以理解,下面的案例稍微容易些:

    fun main() = runBlocking {
        launch {
            println("test3")
        }
        println("test1")
        coroutineScope {    //挂起runBlocking,直到内部逻辑完成
            println("test2")
            delay(1000)     //挂起runBlocking5s
            println("test4")
        }
        println("test5")    //必须等待挂起函数coroutineScope执行完毕后才会被执行
    }
    //test1
    //test2
    //test3
    //test4
    //test5
    

    而如果把coroutineScope函数改成delay函数,会更加容易理解,因为它们都是挂起函数。

    fun main() = runBlocking {
        launch {
            delay(1000)
            println("test2")
        }
        println("test1")
        delay(2000)     //挂起runBlocking协程2s
        println("test3")
    }
    
    //test1
    //test2
    //test3
    

    coroutineScope经常用来把一个长耗时的任务拆分成多个子任务,使这些子任务并行执行

    suspend fun showSomeData() = coroutineScope {
        val data1 = async {         //子任务1
            delay(2000)
            100
        }
        val data2 = async {         //子任务2
            delay(3000)
            20
        }
        
        withContext(Dispatchers.Default) {      //合并结果并返回
            delay(3000)
            val random = Random(10)
            data1.await() + data2.await() + random.nextInt(100)
        }
    }
    

    coroutineScope有如下语义:

    1. 并行执行内部任务data1data2withContext

    2. 如果其它任务(random)抛出异常,data1data2两个任务会被取消

    3. 如果showSomeData()被取消,内部的data1data2withContext都会被取消

    4. 如果data1data2失败,withContext被取消。

    相关文章

      网友评论

        本文标题:kotlin协程--coroutineScope函数

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