kotlin coroutines,coroutineScope和withContext有什么区别

kotlin coroutines, what is the difference between coroutineScope and withContext

1
2
3
4
5
6
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.

1
2
3
4
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 contexta€?s Job.

withContext使用CoroutineContext,并且在所有子级完成后,两者似乎都是complete

在哪种情况下,应优先使用withContextcoroutineScope

例如:

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

也可能是

1
2
3
4
5
6
suspend fun processAllPages() = coroutineScope {
    // coroutineScope waits for all children coroutines
    launch { processPages(urls, collection) }
    launch { processPages(urls, collection2) }
    launch { processPages(urls, collection3) }
}

两个processAllPages()都在做同样的事情吗?

更新:请参见"为什么withContext等待子协程的完成"中的讨论


形式上,coroutineScopewithContext的特例,您可以在其中传递当前上下文,从而避免任何上下文切换。从概念上讲,

1
coroutineScope a‰? withContext(this.coroutineContext)

由于切换上下文只是withContext的几个功能之一,因此这是一个合法的用例。 withContext等待您在块中启动的所有协程完成。如果它们中的任何一个失败,它将自动取消所有其他协程,并且整个块将引发异常,但不会自动取消您从中调用它的协程。

无论何时需要这些功能而无需切换上下文,都应始终首选coroutineScope,因为它可以更清楚地表明您的意图。

coroutineScope关于几个子协程的作用域生命周期。它用于将一个任务分解为多个并发子任务。您无法使用它更改上下文,因此它从当前上下文继承Dispatcher。通常,如果需要,每个子协程将指定不同的Dispatcher

withContext通常不用于启动子协程,而是临时切换当前协程的上下文。它应在其代码块完成后立即完成(从1.3.2版开始,实际上仍在其文档中说明)。它的主要用例是将较长的操作从事件循环线程(例如主GUI线程)转移到使用其自己的线程池的Dispatcher上。另一个用例是定义"关键部分",在该部分中协程将不会对取消请求做出反应。