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
}
}
}
val scope = CoroutineScope(context = Dispatchers.IO)
val job = scope.launch {
val result = suspendFunc1()
suspendFunc2(result)
}
// ...
scope.cancel() // suspendFunc1() and suspendFunc2() will be cancelled
3条答案
按热度按时间6ioyuze21#
它们确实是紧密相关的,你可以说
CoroutineScope
形式化了CoroutineContext
的继承方式。CoroutineScope
本身没有数据,它只保存了一个CoroutineContext
,它的关键作用是作为你传递给launch
,async
等的块的隐式接收者。请看这个例子:
您可以看到
CoroutineScope
如何协调协程上下文的继承,如果您取消scope1
中的作业,这将传播到scope2
,并且也将取消launch
ed作业。注意关键的语法特征:我显式地编写了
scope0.launch
,但是如果我只编写launch
,它的隐式含义完全相同,这就是CoroutineScope
帮助"自动"传播作用域的方式。xqkwcwgp2#
是的,原则上你是对的,这里有更多的细节。
viewModelScope
)以避免泄漏的方法协程上下文是一组不同的元素,主要元素是协程的Job(我们之前见过)及其调度程序[...]. (Source)
如果你指定了一个调度器,有四个选项基本上决定了协程将在哪个线程上运行:
Dispatchers.Default
**-用于CPU密集型工作(例如,对大列表进行排序)Dispatchers.Main
**-这将取决于您添加到程序运行时依赖项的内容(例如kotlinx-coroutines-android
,用于Android中的UI线程)Dispatchers.Unconfined
**-在非特定线程上不受限制地运行协程Dispatchers.IO
**-用于繁重的IO工作(例如长时间运行的数据库查询)下面的例子将作用域和上下文放在一起。它创建了一个新的作用域,在这个作用域中,协程将在指定用于IO工作的线程上运行(如果没有改变),并通过它们的作用域取消它们。
bmvo0sr53#
x一个m0n1x有一个x一个m1n1x。
例如,如果您有:
runBlocking
定义了launch
继承的CoroutineScope
(了解它here)。通过在此处显式指定调度程序将覆盖上下文。如果查看launch
的定义,可以看到它采用可选的CoroutineContext
:上下文的另一部分是协程的名称: