網站首頁 編程語言 正文
正文
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
函數,創建一個新的協程作用域,并在該作用域內執行指定代碼塊,它并不啟動協程。其存在的目的是進行符合結構化并發的并行分解(即,將長耗時任務拆分為并發的多個短耗時任務,并等待所有并發任務完成后再返回)。
coroutineScope
與runBlocking
的區別在于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
代碼分析
-
runBlocking
在main
線程創建并啟動一個阻塞的協程; - 創建
launch①
子協程,由于創建協程是需要一些時間的,并且協程的創建是由特定的線程來完成,并非是main線程。所以在創建協程過程中會并行地執行后續代碼。因此test1
被輸出。 - 執行到
coroutineScope
函數時,把runBlocking
掛起,直到內部邏輯執行完成。 - 然后創建
launch②
協程,創建過程中執行執行后續代碼:delay①
繼續掛起runBlocking
5s(掛起函數中調用掛起函數)。 - 等到
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
)拋出異常,data1
和data2
兩個任務會被取消 - 如果
showSomeData()
被取消,內部的data1
、data2
、withContext
都會被取消 - 如果
data1
、data2
失敗,withContext
被取消。
原文鏈接:https://www.jianshu.com/p/c357ac7660cb
相關推薦
- 2022-04-19 基于HarmonyOS的ArkUI編寫的社區類app(四)———倒計時控制和驗證碼登錄功能的實現
- 2022-05-24 Django框架cookie和session方法及參數設置_python
- 2022-07-08 Python基礎篇之字符串的最全常用操作方法匯總_python
- 2023-04-03 PyTorch中Torch.arange函數詳解_python
- 2023-10-18 如何在linux中安裝ssh服務
- 2022-10-18 Golang?內存管理簡單技巧詳解_Golang
- 2022-03-27 Android實現井字游戲_Android
- 2023-04-26 Numpy對于NaN值的判斷方法_python
- 最近更新
-
- window11 系統安裝 yarn
- 超詳細win安裝深度學習環境2025年最新版(
- Linux 中運行的top命令 怎么退出?
- MySQL 中decimal 的用法? 存儲小
- get 、set 、toString 方法的使
- @Resource和 @Autowired注解
- Java基礎操作-- 運算符,流程控制 Flo
- 1. Int 和Integer 的區別,Jav
- spring @retryable不生效的一種
- Spring Security之認證信息的處理
- Spring Security之認證過濾器
- Spring Security概述快速入門
- Spring Security之配置體系
- 【SpringBoot】SpringCache
- Spring Security之基于方法配置權
- redisson分布式鎖中waittime的設
- maven:解決release錯誤:Artif
- restTemplate使用總結
- Spring Security之安全異常處理
- MybatisPlus優雅實現加密?
- Spring ioc容器與Bean的生命周期。
- 【探索SpringCloud】服務發現-Nac
- Spring Security之基于HttpR
- Redis 底層數據結構-簡單動態字符串(SD
- arthas操作spring被代理目標對象命令
- Spring中的單例模式應用詳解
- 聊聊消息隊列,發送消息的4種方式
- bootspring第三方資源配置管理
- GIT同步修改后的遠程分支