Kotlin 为什么'async'不';如果直接在协同程序块内调用,是否继承SupervisorJob?
给出以下代码片段: 片段[1]Kotlin 为什么'async'不';如果直接在协同程序块内调用,是否继承SupervisorJob?,kotlin,kotlin-coroutines,Kotlin,Kotlin Coroutines,给出以下代码片段: 片段[1] val job = SupervisorJob() val scope = CoroutineScope(Dispatchers.IO + job) scope.launch { try { scope.async { throw RuntimeException("Oops!") }.await() } catch(e: Exception) { // Handle exception } } 和片段
val job = SupervisorJob()
val scope = CoroutineScope(Dispatchers.IO + job)
scope.launch {
try {
scope.async {
throw RuntimeException("Oops!")
}.await()
} catch(e: Exception) {
// Handle exception
}
}
和片段[2]
val job = SupervisorJob()
val scope = CoroutineScope(Dispatchers.IO + job)
scope.launch {
try {
async {
throw RuntimeException("Oops!")
}.await()
} catch(e: Exception) {
// Handle exception
}
}
第一个代码段有效,第二个代码段崩溃。一般的解释是,在第一种情况下,async
从scope
继承SupervisorJob
,而在第二种情况下,不继承
我的问题是,如果
async
是CoroutineScope
的扩展函数,为什么在第二种情况下(崩溃),它不以相同的方式继承SupervisorJob
?launch
创建一个新作业,并将其传播到块接收的CoroutineScope
。在第二个代码段中,async
作业是launch
作业的子作业,launch
作业在其子作业失败时被取消
在第一个代码段中,
async
作业是您创建的SupervisorJob
的子作业,当其子作业失败时,不会取消该子作业。本例中的launch
作业没有子项。它只捕获异常并完成。在您的第一个代码段中,因为您显式地重写了启动
生成器所建立的作用域,所以它与内部的异步
块之间没有父子关系
这是编写第一个代码段的等效方法:
val deferred = scope.async {
throw RuntimeException()
}
scope.launch {
try {
deferred.await()
} catch(e: Exception) {
}
}
async
协同程序失败,出现异常。它的父级是一个监管者作业
,它忽略了失败。launch
coroutine调用了Deferred.await()
,这会引发异常。您捕获了异常,但没有失败
您的第二个代码段可以重写如下:
scope.launch {
val innerScope = this
innerScope.async {
throw RuntimeException()
}
}
在这里,您可以明确地看到
async
块继承了哪个范围。它不是具有SupervisorJob
的顶级作业,而是创建的launch
内部作业。当async
corroutine失败时,父作业将首先取消所有其他子作业(在本例中为无子作业),然后取消其自身。deferred.await()
语句在这里没有区别,这就是我删除它的原因。launch
coroutine将自动等待所有子coroutine完成。在第二个代码段中,在async
范围中,父进程将是谁?父进程是与launch
ed coroutine关联的作业。