提问者:小点点

协程范围生成器流的工作原理


静态编程语言说

  • runBlock方法阻塞当前线程等待
  • coroutineScope只是挂起,释放底层线程以供其他用途使用。
  • 因此runBlock是一个常规函数,而coroutineScope是一个挂起函数
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
}

在上面的例子中,我期望的是:-

  • runBlock阻塞主线程,启动将执行,并且涉及延迟(200L)
  • 因此,底层协程被释放并运行coroutineScope并到达延迟(500L)

这是我对runBlockcoroutineScope的理解。这并不像预期的那样工作。

的输出是

Task from coroutine scope
Task from runBlocking
Task from nested launch
Coroutine scope is over

谁能好心地用简单的方式解释一下这一点。


共2个答案

匿名用户

启动导致块被异步执行,因此对启动的调用立即返回,协程继续运行,不等待启动块的执行。

因此,在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

    这是因为就像runBlockcoroutineScope通过挂起底层线程来等待其所有成员执行。但是要明白,这些线程首先在coroutineScope的成员上工作,而不是在runBlock上。

    因此,在协程作用域结束之前,它从协程作用域打印Task和从嵌套启动打印Task