kotlin协程--coroutineScope函数

public suspend fun  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函数)