Kotlin Coroutine SupervisorJob 取消行为
Kotlin Coroutine SupervisorJob canceling behaviour
代码:
viewModelScope.launch(CoroutineExceptionHandler { _, _ ->
Log.e("TAG", "task 1")
}) {
try {
Log.e("TAG", "task 1 start")
delay(3000)
Log.e("TAG", "task 1 finished")
} catch (ex: Exception) {
Log.e("TAG", "task 1 cancelled " + ex)
}
}
launch = viewModelScope.launch(CoroutineExceptionHandler { _, _ ->
Log.e("TAG", "handler 1" + myJob?.isCancelled)
}) {
myJob = SupervisorJob()
launch(myJob!! + CoroutineExceptionHandler { _, _ ->
Log.e("TAG", "handler 2 " + myJob?.isCancelled)
}) {
delay(300)
launch {
try {
Log.e("TAG", "task 2 start")
delay(5000)
Log.e("TAG", "task 2 finished")
} catch (ex: Exception) {
Log.e("TAG", "task 2 ex " + ex)
}
}
launch {
delay(2000)
throw Exception()
}
}
launch {
try {
Log.e("TAG", "task 3 start")
delay(3000)
Log.e("TAG", "task 3 finished")
} catch (ex: Exception) {
Log.e("TAG", "task 3 ex " + ex)
}
}
}
输出:
2020-01-06 09:47:56.462 7159-7159/? E/TAG: task 1 start
2020-01-06 09:47:56.496 7159-7159/? E/TAG: task 3 start
2020-01-06 09:47:56.798 7159-7159/com.mvvm.template.debug E/TAG: task 2 start
2020-01-06 09:47:58.822 7159-7159/com.mvvm.template.debug E/TAG: task 2 ex kotlinx.coroutines.JobCancellationException: Parent job is Cancelling; job=StandaloneCoroutine{Cancelling}@81a8e39
2020-01-06 09:47:58.827 7159-7159/com.mvvm.template.debug E/TAG: handler 2 false
2020-01-06 09:47:59.464 7159-7159/com.mvvm.template.debug E/TAG: task 1 finished
2020-01-06 09:47:59.499 7159-7159/com.mvvm.template.debug E/TAG: task 3 finished
我的问题:
我无法理解为什么当任务 2 是 SupervisorJob 的 child 时被取消,而异常发生在另一个 child。
文档状态:
child 的失败或取消不会导致主管作业失败,也不会影响其他 children,因此主管可以实施自定义策略来处理其作业的失败child仁。
我错过了什么吗?任何帮助将不胜感激。
您的答案就在日志中:
task 2 ex kotlinx.coroutines.JobCancellationException: Parent job is Cancelling;
job=StandaloneCoroutine{Cancelling}@81a8e39
看看 parent 工作:这是一份 StandaloneCoroutine
而不是你的 SupervisorJob
。
写的时候
launch(myJob!!, handler) { ... }
myJob
成为已启动协程的 parent 并且协程本身始终与 launch
函数创建的作业相关联它,类型 StandaloneCoroutine
。在这个协程中,您可以启动更多协程而无需明确指定 parent,这意味着它们的 parent 是协程的工作。这不是主管职位,因此会被取消。
I’m having an issue to understand why task 2 is canceled when it’s a child of SupervisorJob and the exception happened on an other child.
这不是问题的直接答案,因为接受的答案已经很好地回答了这个问题,因为 parent 不是 SupervisorJob
但为了实现使 task2 独立于同级作业的预期行为:
您必须通过以下任一方式使用 SupervisorJob
:
- 使您希望彼此独立的每项任务的
SupervisorJob
parent:
在你的例子中:
val myJob = SupervisorJob()
val launch = viewModelScope.launch(CoroutineExceptionHandler { _, _ ->
Log.e("TAG", "handler 1" + myJob.isCancelled)
}) {
launch(CoroutineExceptionHandler { _, _ ->
Log.e("TAG", "handler 2 " + myJob.isCancelled)
}) {
delay(300)
launch(myJob) { // <<<<<<<<< myJob is the parent
try {
Log.e("TAG", "task 2 start")
delay(5000)
Log.e("TAG", "task 2 finished")
} catch (ex: Exception) {
Log.e("TAG", "task 2 ex $ex")
}
}
launch(myJob) { // <<<<<<<<< myJob is the parent
delay(2000)
throw Exception()
}
}
//......
}
- 在
supervisorScope
suspend function 中添加 child 工作兄弟姐妹
val launch = viewModelScope.launch(CoroutineExceptionHandler { _, _ ->
Log.e("TAG", "handler 1")
}) {
launch(CoroutineExceptionHandler { _, _ ->
Log.e("TAG", "handler 2 ")
}) {
delay(300)
supervisorScope { /// <<<< supervisor scope
launch {
try {
Log.e("TAG", "task 2 start")
delay(5000)
Log.e("TAG", "task 2 finished")
} catch (ex: Exception) {
Log.e("TAG", "task 2 ex $ex")
}
}
launch {
delay(2000)
throw Exception()
}
}
}
//....
}
现在 任务 2 将完成而不会引发 JobCancellationException
代码:
viewModelScope.launch(CoroutineExceptionHandler { _, _ ->
Log.e("TAG", "task 1")
}) {
try {
Log.e("TAG", "task 1 start")
delay(3000)
Log.e("TAG", "task 1 finished")
} catch (ex: Exception) {
Log.e("TAG", "task 1 cancelled " + ex)
}
}
launch = viewModelScope.launch(CoroutineExceptionHandler { _, _ ->
Log.e("TAG", "handler 1" + myJob?.isCancelled)
}) {
myJob = SupervisorJob()
launch(myJob!! + CoroutineExceptionHandler { _, _ ->
Log.e("TAG", "handler 2 " + myJob?.isCancelled)
}) {
delay(300)
launch {
try {
Log.e("TAG", "task 2 start")
delay(5000)
Log.e("TAG", "task 2 finished")
} catch (ex: Exception) {
Log.e("TAG", "task 2 ex " + ex)
}
}
launch {
delay(2000)
throw Exception()
}
}
launch {
try {
Log.e("TAG", "task 3 start")
delay(3000)
Log.e("TAG", "task 3 finished")
} catch (ex: Exception) {
Log.e("TAG", "task 3 ex " + ex)
}
}
}
输出:
2020-01-06 09:47:56.462 7159-7159/? E/TAG: task 1 start
2020-01-06 09:47:56.496 7159-7159/? E/TAG: task 3 start
2020-01-06 09:47:56.798 7159-7159/com.mvvm.template.debug E/TAG: task 2 start
2020-01-06 09:47:58.822 7159-7159/com.mvvm.template.debug E/TAG: task 2 ex kotlinx.coroutines.JobCancellationException: Parent job is Cancelling; job=StandaloneCoroutine{Cancelling}@81a8e39
2020-01-06 09:47:58.827 7159-7159/com.mvvm.template.debug E/TAG: handler 2 false
2020-01-06 09:47:59.464 7159-7159/com.mvvm.template.debug E/TAG: task 1 finished
2020-01-06 09:47:59.499 7159-7159/com.mvvm.template.debug E/TAG: task 3 finished
我的问题:
我无法理解为什么当任务 2 是 SupervisorJob 的 child 时被取消,而异常发生在另一个 child。
文档状态:
child 的失败或取消不会导致主管作业失败,也不会影响其他 children,因此主管可以实施自定义策略来处理其作业的失败child仁。 我错过了什么吗?任何帮助将不胜感激。
您的答案就在日志中:
task 2 ex kotlinx.coroutines.JobCancellationException: Parent job is Cancelling;
job=StandaloneCoroutine{Cancelling}@81a8e39
看看 parent 工作:这是一份 StandaloneCoroutine
而不是你的 SupervisorJob
。
写的时候
launch(myJob!!, handler) { ... }
myJob
成为已启动协程的 parent 并且协程本身始终与 launch
函数创建的作业相关联它,类型 StandaloneCoroutine
。在这个协程中,您可以启动更多协程而无需明确指定 parent,这意味着它们的 parent 是协程的工作。这不是主管职位,因此会被取消。
I’m having an issue to understand why task 2 is canceled when it’s a child of SupervisorJob and the exception happened on an other child.
这不是问题的直接答案,因为接受的答案已经很好地回答了这个问题,因为 parent 不是 SupervisorJob
但为了实现使 task2 独立于同级作业的预期行为:
您必须通过以下任一方式使用 SupervisorJob
:
- 使您希望彼此独立的每项任务的
SupervisorJob
parent:
在你的例子中:
val myJob = SupervisorJob()
val launch = viewModelScope.launch(CoroutineExceptionHandler { _, _ ->
Log.e("TAG", "handler 1" + myJob.isCancelled)
}) {
launch(CoroutineExceptionHandler { _, _ ->
Log.e("TAG", "handler 2 " + myJob.isCancelled)
}) {
delay(300)
launch(myJob) { // <<<<<<<<< myJob is the parent
try {
Log.e("TAG", "task 2 start")
delay(5000)
Log.e("TAG", "task 2 finished")
} catch (ex: Exception) {
Log.e("TAG", "task 2 ex $ex")
}
}
launch(myJob) { // <<<<<<<<< myJob is the parent
delay(2000)
throw Exception()
}
}
//......
}
- 在
supervisorScope
suspend function 中添加 child 工作兄弟姐妹
val launch = viewModelScope.launch(CoroutineExceptionHandler { _, _ ->
Log.e("TAG", "handler 1")
}) {
launch(CoroutineExceptionHandler { _, _ ->
Log.e("TAG", "handler 2 ")
}) {
delay(300)
supervisorScope { /// <<<< supervisor scope
launch {
try {
Log.e("TAG", "task 2 start")
delay(5000)
Log.e("TAG", "task 2 finished")
} catch (ex: Exception) {
Log.e("TAG", "task 2 ex $ex")
}
}
launch {
delay(2000)
throw Exception()
}
}
}
//....
}
现在 任务 2 将完成而不会引发 JobCancellationException