如果我在 Kotlin 协程中编写阻塞代码,它是否仍会阻塞线程?

If I write blocking code inside a Kotlin coroutine will it still block the thread?

这个问题是在与同事广泛讨论后提出的,

问题如下:

在带有延续的 suspendCoroutine 块中调用同步方法之前我在做什么:

private suspend fun <T : Any> request(queryRequest: GraphQLQueryRequest<T>): T? = suspendCoroutine { continuation ->
    val response = graphqlClient.executeQuery(queryRequest.query, queryRequest.variables, executor)
    val item = response.extractValueAsObject("data.${queryRequest.pathAccessor}", queryRequest.type.java)
    continuation.resume(item)
}

他声称我的代码没有阻止线程被阻塞,整个过程将不得不等待我的协程恢复以释放线程。

他的提议:

private suspend fun <T : Any> request(queryRequest: GraphQLQueryRequest<T>): T? {
    val response = graphqlClient.reactiveExecuteQuery(queryRequest.query, queryRequest.variables, executor)
    return response.awaitSingle().extractValueAsObject("data.${queryRequest.pathAccessor}", queryRequest.type.java)
}

reactiveExecuteQuery() 将 return WebFlux Mono,然后我们调用 .awaitSingle() 将 Mono 转换为挂起函数,他声称此方法与第一个不同,不会阻塞线程,一切都会工作正常。

根据documentation for suspendCoroutine

Obtains the current continuation instance inside suspend functions and suspends the currently running coroutine.

对 Kotlin 协程有更多了解的人是否知道这些解决方案是否真的提供了不同的结果?在不阻塞线程的阻塞方面?

如果这不是 suspendCoroutine 的用例,那会是什么?

提前感谢您的任何回复:)

正如@Martin Tarjányi 已经提到的,您的同事大体上是正确的。

awaitSingle是一个挂起函数,在documentation中可以看到。这意味着调用它会暂停协程,但其他协程仍然可以 运行 在同一个 Dispatcher.

有时,没有其他解决方案,当库仅提供阻塞 API 时,您应该 运行 在相对较大的线程池上设置协程。使用您的代码,您将 运行 在调用 request() 的同一个调度程序上,通常 Dispatchers.Default,这等于您的内核数(如果您 运行 在单核上 CPU).