Котлин сопрограммы, в чем разница между coroutineScope и withContext - PullRequest
2 голосов
/ 02 июля 2019
withContext
suspend fun <T> withContext(
    context: CoroutineContext, 
    block: suspend CoroutineScope.() -> T
): T (source)
Calls the specified suspending block with a given coroutine context, suspends until it completes, and returns the result.
suspend fun <R> coroutineScope(
    block: suspend CoroutineScope.() -> R
): R (source)
Creates a CoroutineScope and calls the specified suspend block with this scope. The provided scope inherits its coroutineContext from the outer scope, but overrides the context’s Job.

withContext принимает CoroutineContext, и оба они кажутся complete после того, как все его дочерние элементы завершены.

В каком случае withContext или coroutineScope должны быть предпочтительнее, чем другие?

например:

suspend fun processAllPages() = withContext(Dispatchers.IO) { 
    // withContext waits for all children coroutines 
    launch { processPages(urls, collection) }
    launch { processPages(urls, collection2) }
    launch { processPages(urls, collection3) }
}

также может быть

suspend fun processAllPages() = coroutineScope { 
    // coroutineScope waits for all children coroutines 
    launch { processPages(urls, collection) }
    launch { processPages(urls, collection2) }
    launch { processPages(urls, collection3) }
}

оба processAllPages() делают то же самое?


обновление: см. Обсуждение на Почему withContext ожидает завершения дочерних сопрограмм

1 Ответ

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

Это два случая, когда обе функции видимости ведут себя одинаково:

withContext(coroutineContext) { ... }
coroutineScope { ... }

Оба ожидают завершения всех сопрограмм, которые вы запускаете в блоке.Если какой-либо из них завершится неудачно, оба автоматически отменит все другие сопрограммы, и весь блок сгенерирует исключение, но не отменит автоматически сопрограмму, из которой вы их вызываете.

Однако независимо от того жеповедение, каждая функция имеет свое назначение и сигнализирует о другом намерении.

coroutineScope - это жизненный цикл нескольких подпрограмм.Он используется для разделения задачи на несколько одновременных подзадач.С ним нельзя изменить контекст, поэтому он наследует Dispatcher от текущего контекста.Как правило, каждая подпрограмма будет указывать различный Dispatcher при необходимости.

withContext не используется для запуска подпрограмм, она заставляет текущую сопрограмму временно переключать контексты и должна завершиться, как только ее кодблок завершается.Его основным вариантом использования является разгрузка длинной операции из потока цикла событий (такого как основной поток GUI) в Dispatcher, который использует свой собственный пул потоков.Другой вариант использования - определение «критической секции», в которой сопрограмма не будет реагировать на запросы отмены.

...