何时使用 coroutineScope 与 supervisorScope?

When to use coroutineScope vs supervisorScope?

谁能解释一下这两者到底有什么区别?

你什么时候用一个代替另一个?

提前致谢。

我认为Roman Elizarov explain it quite in details,但简而言之:

协程创建以下类型的层次结构:

  • 父协程
    • 子协程 1
    • 子协程 2
    • ...
    • 子协程 N

假设“Coroutine i”失败。你希望它的父级发生什么?

如果您希望其父级也失败,请使用 coroutineScope。这就是结构化并发的意义所在。

但是如果你不希望它失败,例如 child 是某种可以再次启动的后台任务,那么使用 supervisorScope

解释差异的最好方法是解释 coroutineScope 的机制。考虑这段代码:

suspend fun main() = println(compute())

suspend fun compute(): String = coroutineScope {
    val color = async { delay(60_000); "purple" }
    val height = async<Double> { delay(100); throw HttpException() }
    "A %s box %.1f inches tall".format(color.await(), height.await())
}

compute()从网络上抓取两个东西,组合成一个字符串描述。在这种情况下,第一次获取需要很长时间,但最终会成功;第二个在 100 毫秒后几乎立即失败。

您希望上述代码有什么行为?

  1. 要不要color.await()一分钟,才发现对方网络调用早就失败了?

  2. 或者您可能希望 compute() 函数在 100 毫秒后意识到其网络调用之一失败并立即自行失败?

supervisorScope 你得到 1.,coroutineScope 你得到 2.

2. 的行为意味着,即使 async 本身不抛出异常(它只是完成了你从它那里得到的 Deferred),失败会立即取消它的协程,这取消了 parent,然后取消了所有其他 children。

当您没有意识到时,这种行为可能会很奇怪。如果你去捕获来自 await() 的异常,你会认为你已经从中恢复过来,但你没有。整个协程作用域仍在取消中。在某些情况下,您不想要它是有正当理由的:那就是您将使用 supervisorScope.

主要区别在于协程作用域将在其任何 children 失败时取消。如果我们想在一个任务失败时继续执行其他任务,我们可以使用 supervisorScope。当其中一个失败时,supervisorScope 不会取消其他 children。

这里有一个有用的link,可以详细理解协程:

https://blog.mindorks.com/mastering-kotlin-coroutines-in-android-step-by-step-guide