Asynchronous 用kotlin协程并行分解独立异步任务
我试图并行运行多个任务,但这些任务是独立的,因此如果其中一个子协同程序失败,我不希望它的兄弟姐妹或父节点也失败。在下面的代码中,我使用了coroutineScope创建了一个新的作用域,在这个作用域中,这些任务运行并启动了5个异步任务,每个任务发送其id和它应该等待的延迟时间。第二个协同程序抛出一个异常。在本例中,代码执行我希望它执行的操作,它计算成功完成的作业和失败的作业的总和,返回0 然而,我读到kotlinx库中也有supervisorScope,这应该是首选,而不是coroutineScope(如果未处理异常,则取消父级/同级),因为任务不依赖于其他任务。我不知道为什么我应该改用supervisorScope,因为我用coroutineScope得到了我想要的结果 Q1:如果我要切换到supervisorScope,我的异步块是否会发生变化 Q2:是否接受捕获异步块内的任何异常,并且不让任何内容传播到其父块?我知道您也可以在.await()阶段捕获异常,但这是应该做的吗Asynchronous 用kotlin协程并行分解独立异步任务,asynchronous,kotlin,coroutine,kotlin-coroutines,Asynchronous,Kotlin,Coroutine,Kotlin Coroutines,我试图并行运行多个任务,但这些任务是独立的,因此如果其中一个子协同程序失败,我不希望它的兄弟姐妹或父节点也失败。在下面的代码中,我使用了coroutineScope创建了一个新的作用域,在这个作用域中,这些任务运行并启动了5个异步任务,每个任务发送其id和它应该等待的延迟时间。第二个协同程序抛出一个异常。在本例中,代码执行我希望它执行的操作,它计算成功完成的作业和失败的作业的总和,返回0 然而,我读到kotlinx库中也有supervisorScope,这应该是首选,而不是coroutineSc
runBlocking {
coroutineScope {
val job1 = async<Int> {
try {
request(1, 1000)
} catch (e: Exception) {
println("Job 1 failed with $e")
0
}
}
val job2 = async<Int> {
try {
request(2, 2000)
throw Exception("cancelling Job 2")
} catch (e: Exception) {
println("Job 2 failed: $e")
0
}
}
val job3 = async {
try {
request(3, 3000)
} catch (e: Exception) {
println("Job 3 failed with $e")
0
}
}
val job4 = async {
try {
request(4, 4000)
} catch (e: Exception) {
println("Job 4 failed with $e")
0
}
}
val job5 = async {
try {
request(5, 5000)
} catch (e: Exception) {
println("Job 5 failed with $e")
0
}
}
val result = job1.await() + job2.await() + job3.await() + job4.await() + job5.await()
println(result.toString())
}
println("Finished")
}
所有协同程序运行到完成的原因是,您在作业2本身中捕获了作业2引发的异常,因此它不会向上传播到作业的层次结构中,因此不会发生任何事情 但是,如果删除job2中的
catch
子句,作业[1-5]将始终被取消,这与使用coroutineScope
或supervisorScope
无关
这是因为job2.await()
将引发异常。由于这发生在作业[1-5]的父作业内(即在顶部的协同工作范围内
/主管范围
),并且由于失败/取消的父作业总是取消子作业,因此作业[1-5]也将被取消
A1:不要使用coroutineScope
或supervisorScope
,删除coroutineScope
,并将内容直接放在运行阻塞
下
A2:当然可以在
async{}
中捕获异常,以确保它不会在中发生。wait()
如果它适合您的用例。好的,这是有意义的。那么应该采取什么样的方法呢?无论我使用coroutineScope
或supervisorScope
还是有更惯用的方法来处理这个问题,我都不明白在这种情况下为什么需要coroutineScope
。继续做你要做的事情,即捕获失败子作业中的异常并使它们返回0,然后像你已经做的那样求和。只需删除当前的coroutineScope
,并将所有内容直接移动到runBlocking
下,就完成了。(当然,您可能想添加一些帮助函数以减少代码重复。当然,您也不应该在实际代码中使用runBlocking
,但我怀疑您不会)。是的,这只是我提出的一个示例代码,但想法类似,我只是在一个循环中创建异步协程,因此我围绕它们创建了一个协程作用域。是的,我的代码中没有使用runBlocking是的,这里有一个输入错误
suspend fun request(id: Int, time: Long): Int {
println("Job $id started")
delay(time)
println("Job $id finished")
return id
}