问题描述
任何人都可以在功能CoroutineScope()
和coroutineScope()
之间明确吗?
Can anyone give clarity between functions CoroutineScope()
and coroutineScope()
?
当我尝试检入源代码时,我发现它们都是CoroutineScope.kt
的功能.另外,coroutineScope()
是suspend
函数,而另一个是normal
函数
When I tried to check in source, I found that both of them are functions of CoroutineScope.kt
. Additionally, coroutineScope()
is suspend
function while other one is normal
function
下面是我可以找到的文档:
Below is documentation I could find :
/**
* 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())
还有
/**
* 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)
}
我想弄清楚它们之间的区别.如果任何人都可以回答何时使用哪一个,那会有所帮助.
I want to get clear difference between them. If anyone can answer when to use which one, it would be helpful.
推荐答案
CoroutineScope
(大写C版本)与coroutineScope
(小版本c版本)之间的最大区别是,我可以弄清楚它们之间的相关性很容易理解非结构化与结构化并发
Best difference between CoroutineScope
(Capital C version) vs coroutineScope
(Smaller c version), I could figure out and which was easily understandable was correlating them with Unstructured vs Structured concurrency
让我分享一个例子:
class MainActivity extends Activity {
private Button btn;
public void onCreate(Bundle b) {
setContentView(R.layout.activity_main);
btn = (Button) findViewById(R.id.start_btn);
btn.setOnClickListener( () -> {
// Starting a coroutine in Main scope, to download user data, and will print it
CoroutineScope(Dispatchers.Main).launch {
int result = downloadUserData()
Toast.makeText(applicationContext, "Result : " + result, Toast.LENGTH_LONG).show()
});
}
private suspend int downloadUserData() {
int 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 (int i = 0; i < 2000; i++) {
kotlinx.coroutines.delay(400);
result++;
}
}
return result;
}
}
输出:Result : 0
这是非结构化并发的示例,其中不能保证子协程会在返回之前完成.因此,调用方/父协程将得到子协程返回的错误值.即使子协程已经返回,子协程也可能在后台运行(处于活动状态),这在某些情况下可能会导致内存泄漏.
This is an example of Unstructured Concurrency where it is not guaranteed that child coroutine would complete before returning. Thus, caller/parent coroutine would get wrong value returned by child coroutine. Even, when child coroutine has returned already, child coroutine may be running (in Active state) in the background which may lead to Memory Leaks in certain cases.
解决方案:
当我们需要在多个协程之间进行通信时,我们需要确保结构化并发(推荐)
When we need to communicate between multiple coroutines, we need to make sure Structured Concurrency (Recommended)
这可以通过在子/被调用协程中重用父/调用方协程范围来完成.这可以通过在子程序/被调用程序协程中使用coroutineScope {}
(Smaller c)版本来实现.
This can be done by re-using parent/caller coroutine scope inside child/callee coroutine. This can be achieved by coroutineScope {}
(Smaller c) version inside child/callee coroutine.
private suspend int downloadUserData() {
int 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 (int i = 0; i < 20000; i++) {
kotlinx.coroutines.delay(400);
result++;
}
}
return result;
}
输出:Result : 20000
这篇关于Kotlin中的CoroutineScope和coroutineScope之间的区别的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!