科特琳说
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
}
在上面的示例中,我期望的是:-
launch
将被执行,并涉及delay(200L)
coroutineScope
并到达delay(500L)
和delay(100L)
println("Coroutine scope is over")
。这就是我对runBlocking
和coroutineScope
的理解。哪个无法正常工作。
输出为
Task from coroutine scope
Task from runBlocking
Task from nested launch
Coroutine scope is over
任何人都可以通过一种简单的方式来理解它。
答案 0 :(得分:2)
launch
导致该块异步执行 ,因此对launch
的调用会立即返回,协程将继续运行,而不会等待执行启动的区块。
因此,在调用runBlocking
之后,立即依次调用第一个launch
和第二个delay(100L)
,并在此之后立即将协程暂停在{{1}}上。
100毫秒后,协程将恢复并打印“协程作用域中的任务”,然后嵌套的协程作用域范围的块的执行结束。协程范围始终等待它启动的所有作业的执行结束,因此在这里等待500ms。
同时,将执行两个启动的块,因此首先打印“ runBlocking的任务”(从开始200毫秒后),然后打印“嵌套启动的任务”(从开始500毫秒后)。
最终,内部启动作业完成后,内部协同程序范围结束等待,外部协同程序继续并打印“协同程序范围已结束”。
这是故事。我希望这对理解代码的执行方式以及打印顺序为何如此有帮助。
答案 1 :(得分:1)
我对您的代码做了一些修改
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)大约等于延迟(30L)的3倍
延迟(200L)大约等于延迟(30L)的6倍
因此,在打印3 Task from coroutine scope
之后和6 Task from nested launch
之后。
然后恰好在此Coroutine scope is over
之后,但是您仍然可以看到循环打印的7,8,9
。
这是因为像runBlocking
coroutineScope
那样,它通过挂起基础线程来等待其所有成员执行。但是请理解,这些线程首先在coroutineScope
的成员上工作,而不是在runBlocking
的成员上工作。
因此,它正在Task from coroutine scope
之前打印Task from nested launch
和Coroutine scope is over