kotlin协程coroutineScope函数
最爱大头猫 人气:0正文
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
被取消。
加载全部内容