Kotlin 为什么'async'不';如果直接在协同程序块内调用,是否继承SupervisorJob?

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 } } 和片段

给出以下代码片段:

片段[1]

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关联的作业。