静态编程语言说
fun main() = runBlocking { // this: CoroutineScope
launch {
delay(200L)
println("Task from runBlocking")
}
coroutineScope { // Creates a coroutine scope
launch {
delay(500L)
println("Task from nested launch")
}
delay(100L)
println("Task from coroutine scope") // This line will be printed before the nested launch
}
println("Coroutine scope is over") // This line is not printed until the nested launch completes
}
在上面的例子中,我期望的是:-
启动
将执行,并且涉及延迟(200L)
coroutineScope
并到达延迟(500L)
这是我对runBlock
和coroutineScope
的理解。这并不像预期的那样工作。
的输出是
Task from coroutine scope
Task from runBlocking
Task from nested launch
Coroutine scope is over
谁能好心地用简单的方式解释一下这一点。
启动
导致块被异步执行,因此对启动
的调用立即返回,协程继续运行,不等待启动块的执行。
因此,在runBlock
被调用后,第一次和第二次启动
被相继调用,紧接着协程在延迟(100L)
上暂停。
100ms后,协程恢复并打印“来自协程范围的任务”,然后嵌套的协程范围的块的执行结束。协程范围总是等待它启动的所有作业的执行结束,所以它在这里等待500ms。
同时,执行了两个已启动的块,因此先打印“Task from runBlock”(距离开始200ms后),然后打印“Task from nested启动”(距离开始500ms后)。
最终,内部启动的作业完成后,内部协程范围完成等待,外部协程继续并打印“协程范围结束”。
故事就是这样,希望对理解代码是如何执行的,为什么打印的顺序是这样有一点帮助。
我稍微修改了一下代码
fun main() = runBlocking(Dispatchers.Default) {
var i = 1
launch {
println("Task from runBlocking")
while (i < 10) {
delay(30L)
println(i++)
}
}
coroutineScope { // Creates a coroutine scope
launch {
delay(200L)
println("Task from nested launch")
}
delay(100L)
println("Task from coroutine scope") // This line will be printed before the nested launch
}
println("Coroutine scope is over")
}
输出
Task from runBlocking
1
2
3
Task from coroutine scope
4
5
6
Task from nested launch
Coroutine scope is over
7
8
9
我的观察是,
>
延迟(100L)等于大约3倍延迟(30L)
延迟(200L)等于大约6倍延迟(30L)
因此,在3来自协程范围的任务
和6来自嵌套启动的任务
被打印之后。
然后就在这个协程作用域结束
之后,您仍然可以看到打印的循环7,8,9
。
这是因为就像runBlock
coroutineScope
通过挂起底层线程来等待其所有成员执行。但是要明白,这些线程首先在coroutineScope
的成员上工作,而不是在runBlock
上。
因此,在协程作用域结束之前,它从协程作用域打印Task
和从嵌套启动打印Task