kotlin协程之coroutineScope函数使用详解

来自:网络
时间:2022-12-26
阅读:
目录

正文

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

代码分析

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

  • 并行执行内部任务data1data2withContext
  • 如果其它任务(random)抛出异常,data1data2两个任务会被取消
  • 如果showSomeData()被取消,内部的data1data2withContext都会被取消
  • 如果data1data2失败,withContext被取消。

以上就是kotlin协程之coroutineScope函数使用详解的详细内容,更多关于kotlin协程coroutineScope函数的资料请关注其它相关文章!

返回顶部
顶部