在下面的代码中,我使用 launch 在scope1中构建了一个协程。我将其作业设置为 Job 的实例,因此任何子作业的取消都会导致父作业被取消。
我使用了
awaitAll
,根据文档,“一旦任何延迟失败,这个awaitAll就会立即失败。”
val scope1 = CoroutineScope(Dispatchers.Default)
val result = IntArray(4)
fun main() = runBlocking {
val parentJob = scope1.launch(Job()) {
val childJobList = (1..4).map { i ->
async {
delay(i.toLong() * 1000.toLong())
if (i == 2) {
cancel()
}
yield()
println("async $i is done")
result[i - 1] = i
}
}
try {
childJobList.awaitAll()
println("Child job completed successfully")
} catch (e: Exception) {
println("Caught exception in parent: ${e.message}")
}
}
parentJob.join()
println("Parent job completed; result = ${result.contentToString()}")
}
然而,事实似乎并非如此。运行代码会产生以下输出:
async 1 is done
Caught exception in parent: DeferredCoroutine was cancelled
async 3 is done
async 4 is done
Parent job completed; result = [1, 0, 3, 4]
有人可以帮忙解释一下为什么会出现这种情况吗?
我不太确定哪个部分让您感到困惑。
awaitAll
显然失败了,我们可以从“在父级中捕获异常:DeferredCoroutine 被取消”日志中看到。您捕获了异常,因此父协程没有失败。
关于这个:
任何孩子的取消都会导致家长的工作被取消。
取消不会传播给父母,只有“真正的”失败才会传播给父母。我们可以在文档中找到对此的多次提及,例如:
如果协程遇到 CancellationException 以外的异常,它会取消其父级并返回该异常。
https://kotlinlang.org/docs/exception-handling.html#cancellation-and-exceptions