为什么withContext等待子协程的完成

时间:2019-07-05 13:30:39

标签: kotlin kotlin-coroutines

withContext国的文档

  

使用给定的协程上下文调用指定的暂停块,直到完成为止暂停并返回结果。

但是,实际行为是它也在所有子协程上等待,并且不一定返回块的结果,而是在子协程中传播任何异常。

suspend fun main() {
    try {
        val result = withContext(coroutineContext) {
            launch {
                delay(1000L)
                throw Exception("launched coroutine broke")
            }
            println("done launching")
            42
        }
        println ("result: $result")
    } catch (e: Exception) {
        println("Error: ${e.message}")
    }
}

我希望上面的命令打印result: 42,然后可能从子协程打印未捕获的异常。而是等待一秒钟,然后打印Error: launched coroutine broke

因此,实际行为与coroutineScope构建器的行为匹配。虽然这可能是有用的行为,但我认为它与文档相矛盾。应该将文档更新为类似于coroutineScope的内容吗?

  

该函数在给定的块及其所有子协程完成后立即返回。

此外,这是否意味着我们可以互换使用coroutineScopewithContext(coroutineContext),唯一的区别是样板要少一些?

1 个答案:

答案 0 :(得分:2)

withContext创建一个新工作。这意味着内部发布的所有协程都是该工作的孩子。仅在作业完成时返回。由于结构化并发,它仅在所有子协程也都完成时才能完成。

任何子作业失败时,父作业将被取消。这也将取消所有其他子项工作。由于withContext返回结果,因此引发了异常。

CoroutineScope中的documentation在这方面很有帮助:

  

每个协程生成器(如启动,异步等)和每个作用域函数(如coroutineScope,withContext等)在其运行的内部代码块中都提供具有自己的Job实例的范围。按照惯例,它们所有人都在等待自己的块中的所有协程完成后再完成自己,从而加强了结构化并发的纪律。

我认为withContext的文档也可以改进。 JobCoroutineContext的文档非常有用,因为它们提供了更高层次的观点。

  

此外,这是否意味着我们可以互换使用coroutineScope和withContext(coroutineContext),唯一的区别是样板要少一些?

是的,它们的行为应相同。它们旨在用于不同的用例。

coroutineScope旨在为多个并行协程提供一个范围,如果有任何失败,所有的协程都将被取消。

withContext旨在用于切换给定代码块的上下文(例如Dispatcher)。

Here是我最近在kotlin论坛上提出的类似问题。该线程包含更多类似的案例和进一步的见识。