在阅读CoroutineScope的介绍和Javadoc之后,我仍然有点困惑CoroutineScope
背后的想法是什么。
文档的第一句话“为新协程定义范围”。我不清楚:为什么我的协程需要一个瞄准镜?
此外,为什么不赞成使用独立的协程构建器?为什么这样做会更好:
fun CoroutineScope.produceSquares(): ReceiveChannel<Int> = produce {
for (x in 1..5) send(x * x)
}
代替
fun produceSquares(): ReceiveChannel<Int> = produce { //no longer an extension function
for (x in 1..5) send(x * x)
}
答案 0 :(得分:5)
您仍然可以通过在GlobalScope
中生成全局“独立”协程来使用它们:
GlobalScope.launch {
println("I'm running unstructured")
}
但是,不建议这样做,因为在全局范围内创建协程与使用良好的旧线程基本相同。您创建了它们,但是以某种方式需要跟踪引用以稍后加入/取消它们。
使用结构化并发,即将协程嵌套在它们的作用域中,您将在总体上拥有一个更易于维护的系统。例如,如果您在另一个内部生成一个协程,则您将继承外部范围。这具有多个优点。如果取消外部协程,则取消将委派给内部协程。另外,您可以确保在所有子协程完成工作之前,外部协程不会完成。
在CoroutineScope
的{{3}}中也显示了一个很好的例子。
CoroutineScope应该在生命周期明确的实体上实施,这些实体负责启动子协程。在Android上此类实体的示例是Activity。
毕竟,显示的produceSquares
方法的第一个版本更好,因为只有在CoroutineScope
中调用时才可执行。这意味着您可以在其他任何协程中运行它:
launch {
produceSquares()
}
在produceSquares
内部创建的协程继承了launch
的范围。您可以确定launch
在produceSquares
之前没有完成。另外,如果您取消了launch
,这也会影响produceSquares
。
此外,您仍然可以像下面这样创建全局运行的协程:
GlobalScope.produceSquares()
但是,如上所述,在大多数情况下,这并不是最佳选择。
我也想推广我写的一篇文章。有一些示例说明了范围的含义:documentation
答案 1 :(得分:2)
它与结构化并发的概念有关,该概念定义了协程之间的结构。
On a more philosophical level,很少像线程那样“全局”启动协程。协程始终与应用程序中的某些本地范围相关,该局部范围是寿命有限的实体,例如UI元素。因此,对于结构化并发,我们现在需要在CoroutineScope中调用启动,CoroutineScope是由您生命周期有限的对象(如UI元素或其相应的视图模型)实现的接口。
这个概念的明显结果是:通过cancel
定义scope
的上下文,所有它的子协程也将被取消。