kotlin协程,coroutineScope和withContext有什么区别

kotlin coroutines, what is the difference between coroutineScope and withContext

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

在什么情况下 withContextcoroutineScope 应该优先于另一个?

例如:

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() 是一样的吗?


更新:参见

的讨论

形式上,coroutineScopewithContext 的特例,您在其中传递当前上下文,避免任何上下文切换。概略地说,

coroutineScope ≡ withContext(this.coroutineContext)

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

每当您需要这些功能而不需要切换上下文时,您应该始终选择 coroutineScope,因为它更清楚地表明您的意图。

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

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