Kotlin:协程作用域与协程上下文

nfg76nw0  于 2023-01-05  发布在  Kotlin
关注(0)|答案(3)|浏览(204)

有人能解释一下它们之间的区别吗?我认为作用域提供了一个引用(例如Job)来取消它们,而上下文提供了一个对底层线程的引用。是这样吗?

6ioyuze2

6ioyuze21#

它们确实是紧密相关的,你可以说CoroutineScope形式化了CoroutineContext的继承方式。
CoroutineScope本身没有数据,它只保存了一个CoroutineContext,它的关键作用是作为你传递给launchasync等的块的隐式接收者。
请看这个例子:

runBlocking {
    val scope0 = this
    // scope0 is the top-level coroutine scope.
    scope0.launch {
        val scope1 = this
        // scope1 inherits its context from scope0. It replaces the Job field
        // with its own job, which is a child of the job in scope0.
        // It retains the Dispatcher field so the launched coroutine uses
        // the dispatcher created by runBlocking.
        scope1.launch {
            val scope2 = this
            // scope2 inherits from scope1
        }
    }
}

您可以看到CoroutineScope如何协调协程上下文的继承,如果您取消scope1中的作业,这将传播到scope2,并且也将取消launch ed作业。
注意关键的语法特征:我显式地编写了scope0.launch,但是如果我只编写launch,它的隐式含义完全相同,这就是CoroutineScope帮助"自动"传播作用域的方式。

xqkwcwgp

xqkwcwgp2#

是的,原则上你是对的,这里有更多的细节。

    • 范围**
  • 协同程序必须在作用域中运行
  • 这是一种跟踪在其中运行所有协程的方法
  • 所有(协作)协程都可以通过它们的作用域取消
  • 作用域获得未捕获的异常
  • 它们是一种将协程绑定到应用程序特定生命周期(例如Android中的viewModelScope)以避免泄漏的方法
    • 背景**

协程上下文是一组不同的元素,主要元素是协程的Job(我们之前见过)及其调度程序[...]. (Source)
如果你指定了一个调度器,有四个选项基本上决定了协程将在哪个线程上运行:

      • Dispatchers.Default**-用于CPU密集型工作(例如,对大列表进行排序)
      • Dispatchers.Main**-这将取决于您添加到程序运行时依赖项的内容(例如kotlinx-coroutines-android,用于Android中的UI线程)
      • Dispatchers.Unconfined**-在非特定线程上不受限制地运行协程
      • Dispatchers.IO**-用于繁重的IO工作(例如长时间运行的数据库查询)

下面的例子将作用域和上下文放在一起。它创建了一个新的作用域,在这个作用域中,协程将在指定用于IO工作的线程上运行(如果没有改变),并通过它们的作用域取消它们。

val scope = CoroutineScope(context = Dispatchers.IO) 
val job = scope.launch {
    val result = suspendFunc1()
    suspendFunc2(result)
}
// ...
scope.cancel() // suspendFunc1() and suspendFunc2() will be cancelled
bmvo0sr5

bmvo0sr53#

x一个m0n1x有一个x一个m1n1x。
例如,如果您有:

runBlocking { // defines coroutineScope

    launch(Dispatchers.Default) { //inherits coroutineScope but changes context

    }
}

runBlocking定义了launch继承的CoroutineScope(了解它here)。通过在此处显式指定调度程序将覆盖上下文。如果查看launch的定义,可以看到它采用可选的CoroutineContext

public fun CoroutineScope.launch(
    context: CoroutineContext = EmptyCoroutineContext,
    ...
)

上下文的另一部分是协程的名称:

launch(CoroutineName("launchMe") + Dispatchers.Default) {
    println("")
}

相关问题