Почему withContext ждут завершения дочерних сопрограмм - PullRequest
2 голосов
/ 05 июля 2019

Документация 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?

Эта функция возвращается, как только данный блок и все его дочерние сопрограммы завершены.

Кроме того, означает ли это, что мы можем использовать coroutineScope и withContext(coroutineContext) взаимозаменяемо, единственное отличие - немного меньший шаблон?

1 Ответ

2 голосов
/ 05 июля 2019

withContext создает новую работу.Это означает, что все сопрограммы, запущенные внутри, являются детьми этой работы.Возвращается только когда работа закончена.Из-за структурированного параллелизма он завершается только тогда, когда завершены также все дочерние сопрограммы.

При сбое любого из дочерних заданий родительское задание отменяется.Это также отменит все другие детские задания.Поскольку withContext возвращает результат, генерируется исключение.

Документация из CoroutineScope полезна в этом отношении:

Каждый строитель сопрограмм (например, launch, async и т. д.), и каждая функция определения объема (например, coroutineScope, withContext и т. д.) предоставляет собственную область видимости со своим собственным экземпляром Job во внутренний блок кода, который она выполняет.По соглашению, они все ждут завершения всех сопрограмм внутри своего блока, прежде чем завершить себя, тем самым обеспечивая дисциплину структурированного параллелизма.

Я думаю, что документация withContext также может быть улучшена.Документация Job и CoroutineContext очень полезна, поскольку она обеспечивает более высокую точку зрения.

Кроме того, означает ли это, что мы можем использовать coroutineScope и withContext (coroutineContext) взаимозаменяемоРазница лишь в том, что шаблон немного меньше?

Да, они должны вести себя одинаково.Они предназначены для разных случаев использования.

coroutineScope предназначено для предоставления области действия для нескольких параллельных сопрограмм, в которых все будут отменены, если произойдет сбой.

withContext предназначен для использования для переключения контекста (например,Диспетчер) для данного блока кода.

Здесь - аналогичный вопрос, который я недавно задавал на форумах kotlin.В ветке есть еще несколько подобных случаев и дальнейшее понимание.

...