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

gao*_*ode 1 async-await kotlin

'await' 的 api 说明:

等待该值完成而不阻塞线程,并在延迟计算完成时恢复,返回结果值或在延迟被取消时抛出相应的异常。

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
}
Run Code Online (Sandbox Code Playgroud)

结果:

开始->1575977567

结束->1575977570

“start”和“end”之间有三秒的间隔。因此,“one.await()”这一行会阻塞线程。为什么和api说的不一样。

hot*_*key 5

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

例如,如果您在函数中添加第二对async { ... }+ ,则调用实际上会同时执行。awaittestAsyncAwaitawait

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

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

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) }
    }
}
Run Code Online (Sandbox Code Playgroud)

两个协程将同时运行,并且one.await()不应阻塞单个线程:

start 0 -> 1575982105
start 1 -> 1575982106
end 0 -> 1575982109
end 1 -> 1575982109
Run Code Online (Sandbox Code Playgroud)

请参阅语言参考中的以下部分: