如何在协程中的一个子任务失败时继续执行

huangapple go评论57阅读模式
英文:

how to continue execution in coroutines when one of the childs fails

问题

我有一个带有两个子协程的作用域。
如果其中一个子协程“崩溃”或抛出异常,我希望另一个子协程能够继续执行。

suspend fun main() {
    val context = Dispatchers.Default + SupervisorJob()
    val scope = CoroutineScope(context = context)
    val job = scope.launch {
        launch() {
            repeat(25) {
                println("子协程 1 $it")
                delay(25)
            }
        }
        launch {
            repeat(20) {
                println("子协程 2 $it")
                delay(18)
                if (it == 16)
                    throw Exception("aaa")
            }
        }
    }
    job.join()
    println("主程序完成")
}

我想实现的是,如果子协程 2 抛出异常,我希望子协程 1 能够继续执行,直到完成其工作。

英文:

I have a scope with two child coroutines inside it
If one of the child "crasches" or throw an exception i want the another child to continue execution

suspend fun main() {
val context = Dispatchers.Default + SupervisorJob()
val scope = CoroutineScope(context = context)
val job = scope.launch {
    launch() {
        repeat(25) {
            println("child 1 $it")
            delay(25)
        }
    }
    launch {
        repeat(20) {
            println("child 2 $it")
            delay(18)
            if (it == 16)
                throw Exception("aaa")
        }
    }
}
job.join()
println("Main finished")

}

What i want to achieve is that if child two throws en exception, i want child one to continue until it finishes is job.

答案1

得分: 2

最简单的方法来解决这个问题不是使用supervisorScope或类似的东西,而是简单地捕获并处理异常。

val job = scope.launch {
    launch() {
        repeat(25) {
            println("child 1 $it")
            delay(25)
        }
    }
    launch {
        try {
          repeat(20) {
            println("child 2 $it")
            delay(18)
            if (it == 16)
                throw Exception("aaa")
          }
        } catch (e : Exception) {
          // 适当记录异常
        }
    }
}
英文:

The simplest way to address this isn't to use a supervisorScope or anything of the sort, but simply to catch and handle the exception.

val job = scope.launch {
    launch() {
        repeat(25) {
            println("child 1 $it")
            delay(25)
        }
    }
    launch {
        try {
          repeat(20) {
            println("child 2 $it")
            delay(18)
            if (it == 16)
                throw Exception("aaa")
          }
        } catch (e : Exception) {
          // log the exception appropriately
        }
    }
}

</details>



# 答案2
**得分**: 1

Wrap the children in a `supervisorScope`:

```kotlin
suspend fun main() {
    val context = Dispatchers.Default + SupervisorJob()
    val scope = CoroutineScope(context = context)
    val job = scope.launch {
        supervisorScope {
            launch {
                repeat(25) {
                    println("child 1 $it")
                    delay(25)
                }
            }
            launch {
                repeat(20) {
                    println("child 2 $it")
                    delay(18)
                    if (it == 16)
                        throw Exception("aaa")
                }
            }
        }
    }
    job.join()
    println("Main finished")
}

Another option is to use an external scope that uses a SupervisorJob to run the other coroutines, but then they are no longer children of this coroutine. You need to join them manually since they are not children. So usually this is not the way you want to do it.

suspend fun main() {
    val context = Dispatchers.Default + SupervisorJob()
    val scope = CoroutineScope(context = context)
    val job = scope.launch {
        val job1 = scope.launch {
                repeat(25) {
                    println("child 1 $it")
                    delay(25)
                }
            }
        val job2 = scope.launch {
                repeat(20) {
                    println("child 2 $it")
                    delay(18)
                    if (it == 16)
                        throw Exception("aaa")
                }
            }
        job1.join()
        job2.join()
    }
    job.join()
    println("Main finished")
}
英文:

Wrap the children in a supervisorScope:

suspend fun main() {
    val context = Dispatchers.Default + SupervisorJob()
    val scope = CoroutineScope(context = context)
    val job = scope.launch {
        supervisorScope {
            launch {
                repeat(25) {
                    println(&quot;child 1 $it&quot;)
                    delay(25)
                }
            }
            launch {
                repeat(20) {
                    println(&quot;child 2 $it&quot;)
                    delay(18)
                    if (it == 16)
                        throw Exception(&quot;aaa&quot;)
                }
            }
        }
    }
    job.join()
    println(&quot;Main finished&quot;)
}

Another option is to use an external scope that uses a SupervisorJob to run the other coroutines, but then they are no longer children of this coroutine. You need to join them manually since they are not children. So usually this is not the way you want to do it.

suspend fun main() {
    val context = Dispatchers.Default + SupervisorJob()
    val scope = CoroutineScope(context = context)
    val job = scope.launch {
        val job1 = scope.launch {
                repeat(25) {
                    println(&quot;child 1 $it&quot;)
                    delay(25)
                }
            }
        val job2 = scope.launch {
                repeat(20) {
                    println(&quot;child 2 $it&quot;)
                    delay(18)
                    if (it == 16)
                        throw Exception(&quot;aaa&quot;)
                }
            }
        job1.join()
        job2.join()
    }
    job.join()
    println(&quot;Main finished&quot;)
}

huangapple
  • 本文由 发表于 2023年6月13日 04:01:39
  • 转载请务必保留本文链接:https://go.coder-hub.com/76459935.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定