【问题标题】:Kotlin await not suspending?Kotlin 等待不暂停?
【发布时间】:2018-09-20 21:13:55
【问题描述】:

我在 Kotlin 中有以下代码

import kotlinx.coroutines.experimental.async
import kotlinx.coroutines.experimental.delay
import kotlinx.coroutines.experimental.runBlocking

fun main(args: Array<String>) {

    runBlocking {
        val async1 = async {
            println("1st")
            delay(2000)
            println("1st end")
        }
        val async2 = async {
            println("2nd")
            delay(1000)
            println("2nd end")
        }

        async1.await()
        async2.await()

        println("end")
    }
}

输出是

1st
2nd
2nd end
1st end
end

我的理解是,await() 是一个挂起函数,这意味着执行在那里“暂停”。所以我想,实际上首先会执行async1,然后会执行async2。所以我希望输出是

1st
1st end
2nd
2nd end    
end

显然发生的事情是,async1async2 都并行执行,这可以看作是 async1 的输出夹在 async2 的输出之间。

所以我现在的具体问题是:为什么 Kotlin 没有在 async1 上暂停,而是同时在 async2 上启动?

【问题讨论】:

    标签: kotlin kotlinx.coroutines


    【解决方案1】:

    await() 将暂停它运行的协程 - 这是你的主块(并且线程 runBlocking() 正在运行,因为它是阻塞的),所以 async2.await() 不会被调用,除非 async1 完成。 但是由于async()函数的执行是立即启动的,并且默认会在后台线程池中执行,所以不会被阻塞。 您可以通过添加来检查它

     async1.await()
     println("between")
     async2.await()
    

    你看,那个“between”总是在“1st end”之后打印出来

    如果您希望协程按顺序运行 - 使用 runBlocking() builder(或者在大多数情况下,这种情况根本不需要使用协程)

    async/await 的想法是并行运行任务,并且在等待其中一个任务的结果时不会阻塞其他任务。

    【讨论】:

    • runBlocking 根本不是关于顺序执行,而是关于阻塞直到协程完成。 withContext(Default) { task() }async { task }.await() 都使 task 与当前协程顺序执行。
    • 谢谢德米特里鲍罗丁!我不知道,async 立即开始。
    【解决方案2】:

    为什么 Kotlin 没有在 async1 上挂起,而是在 async2 上同时启动?

    async 在后台生成一个新任务。任务立即开始执行。您无法控制它的暂停,并且有一整类用例永远不会暂停。我们经常使用async将阻塞任务提交到线程池。

    await 暂停当前协程,直到任务完成并产生结果。它对任务的执行没有影响。即使您从未调用过await,该任务也会运行完成。

    如果你特别想只在调用await时触发任务,你可以指定start = LAZY

    runBlocking {
        val async1 = async(start = LAZY) {
            println("1st")
            delay(2000)
            println("1st end")
        }
        val async2 = async(start = LAZY) {
            println("2nd")
            delay(1000)
            println("2nd end")
        }
    
        async1.await()
        async2.await()
    
        println("end")
    }
    

    这会按您预期的顺序可靠地打印。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2021-03-28
      • 2021-03-27
      • 2013-09-30
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多