Whats the concept behind a CoroutineScope?

ε祈祈猫儿з 提交于 2019-11-28 07:17:35

问题


After reading the introduction and the javadoc of CoroutineScope I'm still a little confused what the idea behind a CoroutineScope is.

The first sentence of the doc "Defines a scope for new coroutines." is not clear to me: Why do my coroutines need a scope?

Also, why are standalone coroutine builders deprecated? Why is it better to do this:

fun CoroutineScope.produceSquares(): ReceiveChannel<Int> = produce {
    for (x in 1..5) send(x * x)
}

instead of

fun produceSquares(): ReceiveChannel<Int> = produce { //no longer an extension function
    for (x in 1..5) send(x * x)
}

回答1:


You can still use global "standalone" coroutines by spawning them in GlobalScope:

GlobalScope.launch {
    println("I'm running unstructured")
}

However, it's not recommended to do this since creating coroutines on a global scope is basically the same we did with good old threads. You create them but somehow need to keep track of a reference to later join/cancel them.

Using structured concurrency, that is nesting coroutines in their scopes, you will have a more maintainable system overall. For example, if you spawn a coroutine inside another one, you inherit the outer scope. This has multiple advantages. If you cancel the outer coroutine, the cancellation will be delegated to its inner coroutines. Also, you can be sure that the outer coroutine will not complete before all its children coroutines have done their work.

There's also a very good example shown in the documentation for CoroutineScope.

CoroutineScope should be implemented on entities with well-defined lifecycle that are responsible for launching children coroutines. Example of such entity on Android is Activity.

After all, the first version of your shown produceSquares methods is better as it is only executable if invoked in a CoroutineScope. That means you can run it inside any other coroutine:

launch {
    produceSquares()
}

The coroutine created inside produceSquares inherits the scope of launch. You can be sure that launch does not complete before produceSquares. Also, if you cancelled launch, this would also effect produceSquares.

Furthermore, you can still create a globally running coroutine like this:

GlobalScope.produceSquares()

But, as mentioned, that's not the best option in most cases.

I'd also like to promote an article I wrote. There are some examples demonstrating what scopes mean: https://kotlinexpertise.com/kotlin-coroutines-concurrency/




回答2:


It is related to the concept of structured concurrency, which defines a structure between coroutines.

On a more philosophical level, you rarely launch coroutines “globally”, like you do with threads. Coroutines are always related to some local scope in your application, which is an entity with a limited life-time, like a UI element. So, with structured concurrency we now require that launch is invoked in a CoroutineScope, which is an interface implemented by your life-time limited objects (like UI elements or their corresponding view models).

As an evident consequence of this concept: by cancelling the context of a scope, all it's subcoroutines will be canceled, too.



来源:https://stackoverflow.com/questions/53412886/whats-the-concept-behind-a-coroutinescope

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!