首页 > 解决方案 > 尝试调用运行阻塞时,带有 Coroutines 的 Kotlin Vertx 阻塞

问题描述

我正在使用公开了回调函数的第三方库。回调函数将在成功时调用。回调函数不是挂起函数,但是当我尝试在非挂起函数内部进行调用以返回挂起函数的结果时,该函数使用 aysnc 和 await 进行 IO 调用,调用永远不会被强制执行。下面我想出了一个简单的代码片段来演示这个问题。

open class TestVerticle: CoroutineVerticle() {

  override suspend fun start() {

    awaitBlockingExample()

  }

 fun awaitBlockingExample():String {

    val future= async(vertx.dispatcher()) {

        makeSuspendFunCall()
     }
     val result:String= runBlocking(vertx.dispatcher()){future.await()}
     println(" The final Result is $result")
     return result
   }

  suspend fun makeSuspendFunCall():String{
    println("Comming here 3")
    delay(500)
    val resp="Test"
    return resp
  }

}
fun main(args: Array<String>) = runBlocking {
    Vertx.vertx().deployVerticle("TestVerticle")
}

如果我删除 makeSuspendFunCall 中的延迟函数,程序运行良好,但如果我添加延迟函数,它会挂起。我实际上是在这里使用延迟函数模拟挂起函数网络调用。在这种情况下,如何从 awaitBlockingExample 获得结果?我清楚地明白,通过将 awaitBlockingExample 作为挂起函数,我可以完成这项工作并删除异步并在内部运行阻塞调用。但是这里 awaitBlockingExample (非挂起函数)代表了一个由本方库提供的实现,它在我们的实现中被覆盖。比如guava缓存提供了reload函数,我想重写reload函数(非挂起函数),并从reload方法中调用协程函数来刷新数据库或网络调用的缓存值。

标签: kotlinvert.xkotlin-coroutinesvertx-verticle

解决方案


问题是它vertx.dispatcher()使用单个线程作为事件循环并runBlocking阻止该线程。

细节:

您的awaitBlockingExample()函数正在此 Vertx 事件循环线程上运行,因为它是从suspend start()函数触发的。如果你调用runBlocking()这个 Vertx 线程被阻塞并且永远不会被释放。但是你的其他协程,例如async(),现在没有线程来完成他们的工作。

解决方案:

我假设awaitBlockingExamplefromstart函数的调用仅在此示例中发生。实际上,我会假设外部回调使用自己的线程。那么就完全没有问题了,因为现在外线程被阻塞了:

override suspend fun start() {

    //simulate own thread for external callback
    thread {
        awaitBlockingExample()
    }
}

fun awaitBlockingExample():String {

    val future= async(vertx.dispatcher()) {

        makeSuspendFunCall()
    }
    val result:String= runBlocking(vertx.dispatcher()){future.await()}
    println(" The final Result is $result")
    return result
}

BTW:你不需要async()块,你可以直接调用makeSuspendFunCall()fromrunBlocking()

fun awaitBlockingExample():String = runBlocking(vertx.dispatcher()){
    val result = makeSuspendFunCall()
    println(" The final Result is $result")
    result
}

推荐阅读