kotlin - 为什么 'await' 会阻塞 kotlin 中的线程?

标签 kotlin async-await

'await' 的 api 描述:

Awaits for completion of this value without blocking a thread and resumes when deferred computation is complete, returning the resulting value or throwing the corresponding exception if the deferred was cancelled.


fun main() = runBlocking {
    val one = async { doSomethingUsefulOne() }
    println("start->" + System.currentTimeMillis() / 1000)
    one.await()
    println("end->" + System.currentTimeMillis() / 1000)
}

suspend fun doSomethingUsefulOne(): Int {
    delay(3000L)
    return 13
}

结果:

开始-> 1575977567

结束->1575977570

'start' 和 'end' 之间有 3 秒的间隔。所以这行 'one.await()' 阻塞了线程。为什么它与 api 所说的不同。

最佳答案

它不一定会阻塞线程。从您传递给 runBlocking { ... } 的 lambda 构建的协程的执行暂停在 one.await()然后恢复一次 one结果准备好了。在此期间,执行协程的线程可以切换到执行另一个协程(如果有的话)。但这不是因为,通过调用 runBlocking { ... } ,您明确指定要在当前单线程中运行协程,独占使用线程直到协程完成,因此当协程挂起并且没有其他协程运行时阻塞线程。

例如,如果您添加第二对 async { ... } + awaittestAsyncAwait函数,await调用实际上将同时执行。

您也可以使用明确支持运行多个协同程序的不同调度程序来运行此协同程序,您会看到 one.await()在这种情况下, call 不会阻塞线程。

例如,您可以按如下方式运行:

suspend fun doSomethingUsefulOne(): Int {
    delay(3000L)
    return 13
}

suspend fun testAsyncAwait(n: Int) = coroutineScope {
    val one = async { doSomethingUsefulOne() }
    println("start $n ->" + System.currentTimeMillis() / 1000)
    one.await()
    println("end $n ->" + System.currentTimeMillis() / 1000)
}

suspend fun main() = coroutineScope {
    val context = newSingleThreadContext("MyOwnThread")
    repeat(2) {
        launch(context) { testAsyncAwait(it) }
    }
}

这两个协程将同时运行,one.await()不应阻塞单个线程:
start 0 -> 1575982105
start 1 -> 1575982106
end 0 -> 1575982109
end 1 -> 1575982109

请参阅语言引用中的这些部分:
  • Coroutine Context and Dispatchers. Dispatchers and threads
  • Coroutine Basics. Bridging blocking and non-blocking worlds
  • 关于kotlin - 为什么 'await' 会阻塞 kotlin 中的线程?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/59266719/

    相关文章:

    android - 意外超越 Kotlin

    kotlin - Kotlin对象表达式无法按预期工作

    kotlin - Kotlin标准函数,如果为null则创建并返回所有结果

    javascript - 如何在 Node Express 中循环调用服务?

    c# - 即使没有异步,CallContext.LogicalGetData 也会恢复。为什么?

    c# - 在方法内返回await fooAsync()或return fooAsync()

    spring-boot - Gradle5.2 中的 Gradle kotlin Unresolved reference : dependtest

    android - 使用 Retrofit + Kotlin Flow 处理错误的优雅方式

    javascript - 在函数内等待/观察

    c# - 仅在需要时将对象包装到任务<object>中