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。
在哪种情况下,应优先使用withContext或coroutineScope?
例如:
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等待子协程的完成"中的讨论
形式上,coroutineScope是withContext的特例,您可以在其中传递当前上下文,从而避免任何上下文切换。从概念上讲,
1
| coroutineScope a‰? withContext(this.coroutineContext) |
由于切换上下文只是withContext的几个功能之一,因此这是一个合法的用例。 withContext等待您在块中启动的所有协程完成。如果它们中的任何一个失败,它将自动取消所有其他协程,并且整个块将引发异常,但不会自动取消您从中调用它的协程。
无论何时需要这些功能而无需切换上下文,都应始终首选coroutineScope,因为它可以更清楚地表明您的意图。
coroutineScope关于几个子协程的作用域生命周期。它用于将一个任务分解为多个并发子任务。您无法使用它更改上下文,因此它从当前上下文继承Dispatcher。通常,如果需要,每个子协程将指定不同的Dispatcher。
withContext通常不用于启动子协程,而是临时切换当前协程的上下文。它应在其代码块完成后立即完成(从1.3.2版开始,实际上仍在其文档中说明)。它的主要用例是将较长的操作从事件循环线程(例如主GUI线程)转移到使用其自己的线程池的Dispatcher上。另一个用例是定义"关键部分",在该部分中协程将不会对取消请求做出反应。
- 谢谢@Marko Topolnik!当您对coroutineScope()说"它用于将一个任务分解为多个并发子任务。"时,这是否也适用于withContext()?除了withContext()可以指定上下文外,它们都将挂起,直到所有子协程完成为止。如果上下文无关紧要,似乎它们都可以在地方使用,不是吗?对于withContext(),它还提到了"This suspending function is cancellable.",这是否意味着如果取消了父/呼叫,它也会被取消?我猜在withContext()中,一个子协程失败不会取消其同级。
-
withContext通常是可取消的挂起函数,但是如果使用NonCancellable上下文,则它将不可取消。请参阅此处以获取更多说明和有启发性的用例。
-
@MarkoTopolnik"它用于将一个任务分解为多个并发子任务",请您详细说明一下。关于" coroutineScope",pl.kotl.in / q55LAN6mB没有并发的内容
-
@FRR您的示例未尝试任何并发。 coroutineScope的目的是启动多个并发子协程并等待它们全部完成,这正是在并行分解任务时需要的。这是一个做到这一点的例子。
-
@MarkoTopolnik感谢您的澄清,我明白您的意思了。因此,此问题的TL; DR将是:是的,withContext和coroutineScope在语义上是同一件事,但是您应该根据自己的意图使用一个或另一个。
-
@FRR它们在语义上仅在特殊情况下相同,即在您不实际切换上下文的情况下调用withContext的情况下,这显然违反了它的预期用途。
-
嗡嗡声,withContext(this.coroutineContext)和coroutineScope不是一回事。 withContext不会等待您在其中享用午餐的子协程,coroutineScope会
-
@DanieleSegato查看此问题。在较早的(实验性?)版本中,它没有等待,但是自从引入结构化并发以来,它就等待了。
-
您是对的,我最初看的代码虽然没有做相同的事情,但是再看一遍(更紧密地看),在相同的上下文中,它们都使用ScopedCoroutine。对不起,误导性评论。
-
任何人都已经足够了,因为两者都造成了本可以避免的混乱。我不知道任何一种用例都可行,而另一种用例却没有。
-
@AbhijitSarkar很简单:withContext(Dispatchers.IO)-coroutineScope在这里不起作用。 Kotlin可能没有coroutineScope生活过,而是要求您编写withContext(this.coroutineContext),但我当然希望在我的代码中不要使用这种看似毫无意义的构造。
-
@MarkoTopolnik常识是withContext,不带任何参数将默认使用当前上下文,但可以提供自定义上下文。太糟糕了,他们没有想到这个简单的主意。
-
@AbhijitSarkar可能有,但是仍然没有任何意义。为什么会有这样的内容:"在当前上下文中继续执行"?作用域不是完全显而易见的,实际上withContext甚至都不打算用于并行分解的用例。该零件在以后的迭代中进行了改装。