coroutineScope 不等待子协程?

coroutineScope doesnt wait for child coroutines?

提问人:steeveKA1 提问时间:9/21/2023 最后编辑:steeveKA1 更新时间:9/22/2023 访问量:46

问:

我尝试在 Kotlin 中学习协程,现在我在 Kotlin Playground 中使用的一些代码有问题。

我有两个挂起函数。一个延迟 3 秒。我将在协程作用域中调用这两个函数。如果我在主程序中调用 getWeatherReport(),我希望它几乎同时打印两条消息,因为它说,协程器等待其所有子协程完成计算,然后返回。 但是为什么这里的 30 度会在 100 毫秒后立即打印出来呢?

来自官方文档:“一旦给定的块及其所有子协程完成,此函数就会返回。 函数返回的确切含义是什么?

suspend fun getWeatherReport() = coroutineScope {


launch { getTemperature() }
launch { getWind() }

}


suspend fun getTemperature(){
delay(100)
println("30 Degrees")
}

suspend fun getWind(){
delay(3000)
println("Wind by North")
}

这就是我在 main 中调用的方式:

fun main(args: Array<String>) {
runBlocking {

   getWeatherReport()
   }
 }
Android Kotlin 异步 作用域 kotlin-coroutines

评论

0赞 dan1st is crying 9/21/2023
当我尝试这样做并在调用后放置一个时,它可以正常工作。你能分享一个 [mcre] 来说明你的问题吗?printlngetWeatherReport()
0赞 Pawel 9/21/2023
目前尚不清楚为什么您预计 println 会延迟到您的持续时间之外。delay
0赞 steeveKA1 9/21/2023
@Pawel为什么不清楚呢?如果我没看错文档,getWeatherReport() 应该只在协程器完成其任务时执行。但是,如果子协程尚未完成,协程器如何向函数发送一些信息呢?
0赞 Pawel 9/21/2023
目前尚不清楚,因为 s 是子协程的一个步骤。无论如何,它们都不是“返回值”。您当前返回的 finished 是无用的。printlngetWeatherInformation()Joblaunch { getWind() }

答:

0赞 Emmanuel Conradie 9/21/2023 #1

您正在创建两个独立的协程。

将两个挂起函数放在同一个启动中,它们将相互等待。

coroutineScope.launch { 
    getTemperature() 
    getWind()
}

正如评论中提到的。如果有两个启动块,则无法保证代码将按顺序执行。

评论

0赞 Steyrix 9/21/2023
应该说,它们将按顺序执行,getTemperature() 将首先执行,然后 getWind()
1赞 Pawel 9/21/2023 #2

让我们用更简单(或者我会说更合适)的情况来解释。coroutineScope

suspend fun getText() = coroutineScope {
    delay(1000)
    println("Block done")
    "Hello world"
}

suspend fun getTextWithChild() = coroutineScope {
    launch {
        delay(3000)
        println("Child done")
    }
    delay(1000)
    println("Block done")
    "Hello world"
}

suspend fun main(args: Array<String>) {
   println(getText())
   println(getTextWithChild())
}

两个 getText 函数都执行它们的主块,我们在一秒钟后打印出“块完成”。此时,它们已准备好返回值“Hello World”。

现在我们可以注意到行为的差异,即“一旦给定块及其所有子协程完成,此函数就会返回”。

在第一种情况下,它很简单 - 因为没有子项,它会立即返回并可以打印“Hello world”。main

在第二种情况下 - 尽管完成了块尚未完成。它仍然有一个在其中启动的活动子作业 - 只有在额外的 2000 毫秒通过后,我们才会看到打印“子完成”,这意味着它已完成,范围可以返回。最后,我们看到 “Hello world” 打印自 .coroutineScopemain

评论

0赞 steeveKA1 9/21/2023
谢谢。现在我完全理解了这个概念。