日本免费高清视频-国产福利视频导航-黄色在线播放国产-天天操天天操天天操天天操|www.shdianci.com

學無先后,達者為師

網站首頁 編程語言 正文

kotlin協程之coroutineScope函數使用詳解_Android

作者:最愛大頭貓 ? 更新時間: 2022-11-02 編程語言

正文

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有如下語義:

  • 并行執行內部任務data1、data2、withContext
  • 如果其它任務(random)拋出異常,data1data2兩個任務會被取消
  • 如果showSomeData()被取消,內部的data1、data2withContext都會被取消
  • 如果data1、data2失敗,withContext被取消。

原文鏈接:https://www.jianshu.com/p/c357ac7660cb

欄目分類
最近更新