kotlin協(xié)程之coroutineScope函數(shù)使用詳解
正文
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) } }
它是一個(gè)suspend
函數(shù),創(chuàng)建一個(gè)新的協(xié)程作用域,并在該作用域內(nèi)執(zhí)行指定代碼塊,它并不啟動(dòng)協(xié)程。其存在的目的是進(jìn)行符合結(jié)構(gòu)化并發(fā)的并行分解(即,將長(zhǎng)耗時(shí)任務(wù)拆分為并發(fā)的多個(gè)短耗時(shí)任務(wù),并等待所有并發(fā)任務(wù)完成后再返回)。
coroutineScope
與runBlocking
的區(qū)別在于runBlocking
會(huì)阻塞當(dāng)前線程,而coroutineScope
會(huì)掛起所在的協(xié)程直至其內(nèi)部任務(wù)(包括子協(xié)程)執(zhí)行完成,它不會(huì)阻塞所在的線程。
coroutineScope
是一個(gè)掛起函數(shù),它被掛起后,會(huì)轉(zhuǎn)而執(zhí)行之前的子協(xié)程。
fun main() = runBlocking { launch { //launch① delay(1000) //掛起launch① println("test2") } println("test1") coroutineScope { //第一次掛起runBlocking,直至內(nèi)部邏輯完成 launch { //launch② delay(2000) //掛起launch② println("test3") } delay(5000) //delay① //第二次掛起runBlocking println("test4") } println("test5") } //test1 //test2 //test3 //test4 //test5
代碼分析
runBlocking
在main
線程創(chuàng)建并啟動(dòng)一個(gè)阻塞的協(xié)程;- 創(chuàng)建
launch①
子協(xié)程,由于創(chuàng)建協(xié)程是需要一些時(shí)間的,并且協(xié)程的創(chuàng)建是由特定的線程來(lái)完成,并非是main線程。所以在創(chuàng)建協(xié)程過(guò)程中會(huì)并行地執(zhí)行后續(xù)代碼。因此test1
被輸出。 - 執(zhí)行到
coroutineScope
函數(shù)時(shí),把runBlocking
掛起,直到內(nèi)部邏輯執(zhí)行完成。 - 然后創(chuàng)建
launch②
協(xié)程,創(chuàng)建過(guò)程中執(zhí)行執(zhí)行后續(xù)代碼:delay①
繼續(xù)掛起runBlocking
5s(掛起函數(shù)中調(diào)用掛起函數(shù))。 - 等到
launch①
創(chuàng)建完畢時(shí),把它掛起1s。launch②
創(chuàng)建完畢時(shí),把它掛起2s。 - 此時(shí)
runBlocking、launch①、launch②
都是被掛起狀態(tài)。 - 等到1s后
launch①
恢復(fù),輸出test2
;2s后launch②
被恢復(fù),輸出test3
;5s后runBlocking
第二次掛起被恢復(fù),輸出test4
。 - 此時(shí)
coroutineScope
中的邏輯已經(jīng)執(zhí)行完成,恢復(fù)runBlocking
的第一次掛起,test5
被輸出。
這比較難以理解,下面的案例稍微容易些:
fun main() = runBlocking { launch { println("test3") } println("test1") coroutineScope { //掛起runBlocking,直到內(nèi)部邏輯完成 println("test2") delay(1000) //掛起runBlocking5s println("test4") } println("test5") //必須等待掛起函數(shù)coroutineScope執(zhí)行完畢后才會(huì)被執(zhí)行 } //test1 //test2 //test3 //test4 //test5
而如果把coroutineScope
函數(shù)改成delay
函數(shù),會(huì)更加容易理解,因?yàn)樗鼈兌际菕炱鸷瘮?shù)。
fun main() = runBlocking { launch { delay(1000) println("test2") } println("test1") delay(2000) //掛起runBlocking協(xié)程2s println("test3") } //test1 //test2 //test3
coroutineScope
經(jīng)常用來(lái)把一個(gè)長(zhǎng)耗時(shí)的任務(wù)拆分成多個(gè)子任務(wù),使這些子任務(wù)并行執(zhí)行
suspend fun showSomeData() = coroutineScope { val data1 = async { //子任務(wù)1 delay(2000) 100 } val data2 = async { //子任務(wù)2 delay(3000) 20 } withContext(Dispatchers.Default) { //合并結(jié)果并返回 delay(3000) val random = Random(10) data1.await() + data2.await() + random.nextInt(100) } }
coroutineScope
有如下語(yǔ)義:
- 并行執(zhí)行內(nèi)部任務(wù)
data1
、data2
、withContext
- 如果其它任務(wù)(
random
)拋出異常,data1
和data2
兩個(gè)任務(wù)會(huì)被取消 - 如果
showSomeData()
被取消,內(nèi)部的data1
、data2
、withContext
都會(huì)被取消 - 如果
data1
、data2
失敗,withContext
被取消。
以上就是kotlin協(xié)程之coroutineScope函數(shù)使用詳解的詳細(xì)內(nèi)容,更多關(guān)于kotlin協(xié)程coroutineScope函數(shù)的資料請(qǐng)關(guān)注腳本之家其它相關(guān)文章!
- Kotlin-Coroutines中的async與await異步協(xié)程管理
- Kotlin?LinearLayout與RelativeLayout布局使用詳解
- Kotlin FrameLayout與ViewPager2控件實(shí)現(xiàn)滾動(dòng)廣告欄方法
- Kotlin協(xié)程啟動(dòng)createCoroutine及創(chuàng)建startCoroutine原理
- Android結(jié)合kotlin使用coroutine的方法實(shí)例
- Kotlin學(xué)習(xí)教程之協(xié)程Coroutine
- kotlin中泛型中in和out的區(qū)別解析
相關(guān)文章
Android編程實(shí)現(xiàn)動(dòng)態(tài)支持多語(yǔ)言的方法
這篇文章主要介紹了Android編程實(shí)現(xiàn)動(dòng)態(tài)支持多語(yǔ)言的方法,涉及Android資源、控件及屬性相關(guān)操作技巧,需要的朋友可以參考下2017-06-06android ListView內(nèi)數(shù)據(jù)的動(dòng)態(tài)添加與刪除實(shí)例代碼
ListView內(nèi)數(shù)據(jù)的動(dòng)態(tài)添加與刪除2013-03-03Android Studio多渠道打包、自定義打包APK名稱(chēng)
Android Studio為我們提供了簡(jiǎn)便的方法,可以多渠道打包,一次打包所有的渠道包。這篇文章主要介紹了Android Studio多渠道打包、自定義打包APK名稱(chēng),需要的朋友可以參考下2018-01-01Android HorizontalScrollView內(nèi)子控件橫向拖拽實(shí)例代碼
本文主要介紹Android HorizontalScrollView的使用,這里給大家一個(gè)實(shí)例來(lái)展示HorizontalScrollView內(nèi)子控件橫向拖拽的效果實(shí)現(xiàn),有需要的小伙伴可以參考下2016-07-07android鬧鈴簡(jiǎn)單實(shí)現(xiàn)
本文給大家分享的是一段簡(jiǎn)單的實(shí)現(xiàn)Android系統(tǒng)的鬧鈴的代碼,非常實(shí)用,想做Android開(kāi)發(fā)的小伙伴們可以參考下。2015-03-03Android開(kāi)發(fā)中關(guān)于獲取當(dāng)前Activity的一些思考
這篇文章主要為大家詳細(xì)介紹了Android開(kāi)發(fā)過(guò)程中,關(guān)于獲取當(dāng)前Activity的一些思考,感興趣的小伙伴們可以參考一下2016-02-02關(guān)于Touch Panel AA區(qū)要做外擴(kuò)的原因解析
今天小編就為大家分享一篇關(guān)于Touch Panel AA區(qū)要做外擴(kuò)的原因解析,小編覺(jué)得內(nèi)容挺不錯(cuò)的,現(xiàn)在分享給大家,具有很好的參考價(jià)值,需要的朋友一起跟隨小編來(lái)看看吧2018-12-12android引導(dǎo)用戶開(kāi)啟自啟動(dòng)權(quán)限的方法
今天小編就為大家分享一篇android引導(dǎo)用戶開(kāi)啟自啟動(dòng)權(quán)限的方法,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過(guò)來(lái)看看吧2018-07-07