如果直接在协程块内调用,为什么 `async` 不继承 SupervisorJob?
Why `async` doesn't inherit SupervisorJob if called directly inside the coroutine block?
给定以下代码片段:
代码段 [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
作业没有子作业。它只是捕获异常并完成。
在您的第一个代码段中,因为您明确覆盖了 launch
构建器建立的范围,所以它与您在其中的 async
块之间没有父子关系。
这是编写第一个片段的等效方法:
val deferred = scope.async {
throw RuntimeException()
}
scope.launch {
try {
deferred.await()
} catch(e: Exception) {
}
}
async
协程因异常而失败。它的父级是 SupervisorJob
,它忽略了失败。 launch
协程调用 Deferred.await()
,这会引发异常。您捕获了异常并且没有任何失败。
您的第二个片段可以重写如下:
scope.launch {
val innerScope = this
innerScope.async {
throw RuntimeException()
}
}
在这里您可以明确地看到 async
块继承了哪个范围。它不是 SupervisorJob
的顶级,而是 launch
创建的内部。当 async
协程失败时,父作业对其作出反应,首先取消所有其他子程序(在本例中为 none),然后取消自身。 deferred.await()
语句在这里没有任何区别,这就是我删除它的原因。 launch
协程将自动等待所有子协程完成。
给定以下代码片段:
代码段 [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
作业没有子作业。它只是捕获异常并完成。
在您的第一个代码段中,因为您明确覆盖了 launch
构建器建立的范围,所以它与您在其中的 async
块之间没有父子关系。
这是编写第一个片段的等效方法:
val deferred = scope.async {
throw RuntimeException()
}
scope.launch {
try {
deferred.await()
} catch(e: Exception) {
}
}
async
协程因异常而失败。它的父级是 SupervisorJob
,它忽略了失败。 launch
协程调用 Deferred.await()
,这会引发异常。您捕获了异常并且没有任何失败。
您的第二个片段可以重写如下:
scope.launch {
val innerScope = this
innerScope.async {
throw RuntimeException()
}
}
在这里您可以明确地看到 async
块继承了哪个范围。它不是 SupervisorJob
的顶级,而是 launch
创建的内部。当 async
协程失败时,父作业对其作出反应,首先取消所有其他子程序(在本例中为 none),然后取消自身。 deferred.await()
语句在这里没有任何区别,这就是我删除它的原因。 launch
协程将自动等待所有子协程完成。