kotlin - 我如何从挂起功能中使用当前的 CoroutineScope `CoroutineScope.async`?

标签 kotlin kotlin-coroutines coroutine

如果我想使用其他挂起函数中的当前CoroutineScope

如何找回它?

下面的代码是我尝试过的。

fun main() = CoroutineScope(Dispatchers.IO).launch {
    val result = getTitleAndLabel() // suspend function
    // doSomthing with result
}
#Case1
// Ambiguous coroutineContext due to CoroutineScope receiver of suspend function
suspend fun CoroutineScope.getTitleAndLabel() {
    val titleDeferred = async { getTitle() }
    val labelDeferred = async { getLabel() }
    val (title, label) = listOf(titleDeferred, labelDeferred).awaitAll()
    return Pair(title, label)
}
#Case2
// It makes another CoroutineScope
suspend fun getTitleAndLabel() = coroutineScope {
    val titleDeferred = async { getTitle() }
    val labelDeferred = async { getLabel() }
    val (title, label) = listOf(titleDeferred, labelDeferred).awaitAll()
    return Pair(title, label)
}
#Case3
// No need to do ContextSwitching
suspend fun getTitleAndLabel() = withContext(Dispatchers.IO) {
    val titleDeferred = async { getTitle() }
    val labelDeferred = async { getLabel() }
    val (title, label) = listOf(titleDeferred, labelDeferred).awaitAll()
    return Pair(title, label)
}
#Case4
// Passing CoroutineScope as an argument?
suspend fun getTitleAndLabel(coroutineScope: CoroutineScope) {
    val titleDeferred = coroutineScope.async { getTitle() }
    val labelDeferred = coroutineScope.async { getLabel() }
    val (title, label) = listOf(titleDeferred, labelDeferred).awaitAll()
    return Pair(title, label)
}

#案例1、#案例2、#案例3、#案例4

最佳答案

我质疑是否需要使用与父协程完全相同的 CoroutineScope。

您的案例 #2 符合您设置的示例。它创建了一个新的作用域,true,但它是一个继承父协程的 CoroutineContext 的作用域,因此如果父协程被取消,它也会被取消。您可以宽松地将其视为协程作用域,尽管实际上不存在任何作用域或上下文的层次结构。

案例 #2 相对于案例 #4 的优点(除了明显更容易使用和避免意外传递与调用父级不同的作用域之外),是它封装了行为。如果其中一个异步任务失败,它会在抛出此挂起函数的调用者之前自动取消另一个任务(以避免浪费时间和资源)。对于情况 #4,此行为将取决于传递的 CoroutineScope 是否具有 SupervisorJob。如果它没有 SupervisorJob,那么这些子进程将导致该范围内的所有协程被取消。通常首选封装,以便从此挂起函数中选择您的行为。

如果您的 aysnc 子协程具有重要的副作用,即使其兄弟协程失败也应该运行,您可以将 coroutineScope { } 替换为 supervisorScope { }。然后,无论它们的 sibling 是否成功,它们都会运行到完成,并且在它们全部完成后,第一个抛出的异常将被重新抛出给挂起函数的调用者。

顺便说一句,在案例 #3 中使用的 withContext 基本上与 coroutineScope 相同,只是它让您有机会覆盖继承的一些参数。协程上下文。它在另一个 CoroutineScope 中运行其内容,就像 coroutineScope { } 所做的那样。

关于kotlin - 我如何从挂起功能中使用当前的 CoroutineScope `CoroutineScope.async`?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/75799460/

相关文章:

Python异步: second coroutine wrapped in a Task is not scheduled (but first is)

python - 如何在 ActionScript 中生成 python/ruby/javascript 样式生成器?

Android协程作业更改为CompletableJob?

android - `bind` 中的 `inflate` , `setContentView` 和 `DataBindingUtil` 有什么区别

kotlin - 如何部分验证数据类作为函数参数?

android - 使用带有 Retrofit 和 Kotlin 的 moshi 将 jsonarray 解析为对象

android - 在 Android 中调试 Kotlins 协程

android - 在后续的挂起方法调用之间发出 LiveData 以更新 UI

c++ - 协程和带有静态变量的函数有什么区别?

java - 我想在 kotlin 中为我的自定义 ImageView 添加圆角