首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >柯特林地区CoroutineScope与coroutineScope的差异

柯特林地区CoroutineScope与coroutineScope的差异
EN

Stack Overflow用户
提问于 2019-12-17 06:42:01
回答 5查看 17.4K关注 0票数 24

有谁能澄清CoroutineScope()coroutineScope()之间的区别吗?

当我试图签入源代码时,我发现它们都是CoroutineScope.kt的函数。另外,coroutineScope()suspend函数,另一个是normal函数。

以下是我可以找到的文件:

代码语言:javascript
复制
/**
 * Creates a [CoroutineScope] that wraps the given coroutine [context].
 *
 * If the given [context] does not contain a [Job] element, then a default `Job()` is created.
 * This way, cancellation or failure or any child coroutine in this scope cancels all the other children,
 * just like inside [coroutineScope] block.
 */
@Suppress("FunctionName")
public fun CoroutineScope(context: CoroutineContext): CoroutineScope =
    ContextScope(if (context[Job] != null) context else context + Job())

代码语言:javascript
复制
/**
 * Creates a [CoroutineScope] and calls the specified suspend block with this scope.
 * The provided scope inherits its [coroutineContext][CoroutineScope.coroutineContext] from the outer scope, but overrides
 * the context's [Job].
 *
 * This function is designed for _parallel decomposition_ of work. When any child coroutine in this scope fails,
 * this scope fails and all the rest of the children are cancelled (for a different behavior see [supervisorScope]).
 * This function returns as soon as the given block and all its children coroutines are completed.
 * A usage example of a scope looks like this:
 *
 * ```
 * suspend fun showSomeData() = coroutineScope {
 *
 *   val data = async(Dispatchers.IO) { // <- extension on current scope
 *      ... load some UI data for the Main thread ...
 *   }
 *
 *   withContext(Dispatchers.Main) {
 *     doSomeWork()
 *     val result = data.await()
 *     display(result)
 *   }
 * }
 * ```
 *
 * The scope in this example has the following semantics:
 * 1) `showSomeData` returns as soon as the data is loaded and displayed in the UI.
 * 2) If `doSomeWork` throws an exception, then the `async` task is cancelled and `showSomeData` rethrows that exception.
 * 3) If the outer scope of `showSomeData` is cancelled, both started `async` and `withContext` blocks are cancelled.
 * 4) If the `async` block fails, `withContext` will be cancelled.
 *
 * The method may throw a [CancellationException] if the current job was cancelled externally
 * or may throw a corresponding unhandled [Throwable] if there is any unhandled exception in this scope
 * (for example, from a crashed coroutine that was started with [launch][CoroutineScope.launch] in this scope).
 */
public suspend fun <R> coroutineScope(block: suspend CoroutineScope.() -> R): R =
    suspendCoroutineUninterceptedOrReturn { uCont ->
        val coroutine = ScopeCoroutine(uCont.context, uCont)
        coroutine.startUndispatchedOrReturn(coroutine, block)
    }

我想弄清楚他们之间的区别。如果有人能回答什么时候使用哪一个,这将是有帮助的。

EN

回答 5

Stack Overflow用户

回答已采纳

发布于 2019-12-17 14:46:43

CoroutineScope (大写C版本)和coroutineScope (较小的c++版本)之间最大的区别,我可以找出,而且很容易理解的是将它们与非结构化结构化并发相关联是可以理解的。

让我举一个例子:

代码语言:javascript
复制
class MainActivity : AppCompatActivity() {
    private lateinit var btn: Button
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)

        btn = findViewById(R.id.start_btn)
        btn.setOnClickListener {
            CoroutineScope(Dispatchers.Main).launch {
                val result = downloadUserData()
                Toast.makeText(applicationContext, "Result : $result", Toast.LENGTH_LONG).show()
            }
        }
    }

    private suspend fun downloadUserData(): Int {
        var result = 0
        // Here, we use CoroutineScope (Capital C version) which will start a new scope and
        // launch coroutine in new scope Dispatchers.IO, Not In Parent Scope which is Dispatchers.Main
        // Thus, this function would directly return without waiting for loop completion and will return 0
        CoroutineScope(Dispatchers.IO).launch {
            for (i in 0 until 100) {
                kotlinx.coroutines.delay(10)
                result++
            }
        }
        return result
    }
}

输出:Result : 0

这是非结构化并发性的一个例子,在该示例中,不能保证子协同器在返回之前完成。因此,调用方/父协同器将获得子协同返回的错误值。甚至,当子coroutine已经返回时,子coroutine可能在后台运行(处于活动状态),在某些情况下可能导致内存泄漏

解决方案:

当我们需要在多个协同机制之间进行通信时,我们需要确保结构化并发(推荐)

这可以通过在子/被调用方内重用父/调用者协同范围来实现。这可以通过coroutineScope {} (较小的c)版本在子/被调用的协同作用中实现。

代码语言:javascript
复制
private suspend fun downloadUserData(): Int {
    var result = 0
    // By using coroutineScope (Smaller c version) below, we ensure that this coroutine would execute in the
    // parent/caller coroutine's scope, so it would make sure that the for loop would complete
    // before returning from this suspended function. This will return 20000 properly
    coroutineScope {
        for (i in 0 until 100) {
            kotlinx.coroutines.delay(10)
            result++
        }
    }
    return result
}

输出:Result : 100

票数 34
EN

Stack Overflow用户

发布于 2019-12-17 09:23:06

CoroutineScope()只不过是CoroutineScope对象的工厂,而CoroutineScope对象只不过是CoroutineContext的持有者。它在协同机制中没有积极的作用,但它是基础设施的一个重要部分,它使正确地执行结构化并发变得容易。这是因为像launchasync这样的协同构建器都是CoroutineScope上的扩展函数,并继承了它的上下文。

如果有的话,您很少需要调用CoroutineScope(),因为通常您要么选择一个现有的协同范围,要么通过其他方便函数(比如安卓上的MainScope )或Kotlin内部函数为您创建一个协同作用域。

另一方面,coroutineScope()是一个函数,它执行在子协同线中传递它的块。它基本上是withContext(this.coroutineContext)的别名,当您想要在前台继续一些工作时启动一个或多个背景协同,然后在完成块时加入到背景协同线中时,您应该主要使用它。

票数 19
EN

Stack Overflow用户

发布于 2020-09-02 09:08:42

他们是完全不同的两件事。

CoroutineScope是定义协同范围概念的接口:要启动和创建协同,需要一个协同。

例如,GlobalScope是一个全局范围的实例。

CoroutineScope()是一个创建CoroutineScope全局函数

当您有一个作用域时,您可以执行launch()async()或任何其他与执行协同机制相关的方法。

代码语言:javascript
复制
// create a context
val myContext = Dispacher.IO
// you can combine dispachers, parent jobs etc.
// create the new scope
val myScope: CoroutineScope = CoroutineScope(myContext)
// returns immediately (unless you specify a start mode that run immediately)
val job = myScope.launch {
  // suspend calls are allowed here cause this is a coroutine
}
// this code is executed right away

您可以在协同线(普通代码)之外执行此操作。

另一方面,coroutineScope()是一个全局挂起函数,它在引擎盖下创建一个新的CoroutineScope,然后执行在主体中传递给它的挂起函数,然后等待它(及其所有子函数)完成后返回。它是一个挂起函数,所以不能在协同线之外调用它。

代码语言:javascript
复制
// must be inside a coroutine here!

// this create a new CoroutineScope,
// then launch the given coroutine,
// then wait for it to complete
val result = coroutineScope {
   // your coroutine here, which run immediately
   return@coroutineScope "my result"
}
// this code is executed after the coroutine above is completed
// I can use "result" here

coroutineScope类似,supervisedScope只有一个不同之处:多个子协同(启动/异步/.)如果其中一个失败,则在内部执行不会取消其他子级,因为它使用了SupervisorJob

票数 8
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/59368838

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档