尝试调用运行阻塞时,带有协程的Koltin Vertx阻塞

时间:2018-11-07 14:27:48

标签: kotlin vert.x kotlinx.coroutines vertx-verticle

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

select * from sample where some_pk =1 and some_id <= 124 limit x;

如果我在makeSuspendFunCall中删除了延迟功能,程序运行会很好,但是如果添加延迟功能,它将被挂起。我实际上是在这里使用延迟功能来模拟暂停功能的网络调用。在这种情况下,如何从awaitBlockingExample获得结果?我清楚地了解到,通过将awaitBlockingExample设置为suspend函数,我可以使它工作并删除异步并在其中运行阻塞调用。但是这里awaitBlockingExample(非暂挂函数)表示此方库提供的实现,该方库在我们的实现中被覆盖。例如,番石榴缓存提供了一个重载功能,我想重写重载功能(非暂停功能)并从重载方法中调用协程函数来刷新数据库或网络调用中的缓存值。

3 个答案:

答案 0 :(得分:3)

问题在于vertx.dispatcher()使用单个线程作为事件循环,而runBlocking阻塞了该线程。

详细信息:

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

解决方案:

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

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
}

顺便说一句:您不需要async()块,可以直接从makeSuspendFunCall()调用runBlocking()

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

答案 1 :(得分:0)

尝试下一种方法:

override fun start() {
    GlobalScope.launch {
        val result = awaitBlockingExample()
    }
}

suspend fun awaitBlockingExample(): String {
    val response =  makeSuspendFunCall()
    println(" The final Result is $response")
    return response
}

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

答案 2 :(得分:0)

对于Kotlin 1.3.0及更高版本

private val mainScope = CoroutineScope(Dispatchers.Main)

fun start(){
        mainScope.launch { 
            val data = withContext(Dispatchers.IO){
                //This function will return the result. Return type of the below function will be type of data variable above.
                awaitBlockingExample()
            }
            //use your data result from async call. Result will be available here as soon as awaitBlockingExample() return it.
        }
        //Your function will continue execution without waiting for async call to finish.
    }

 fun awaitBlockingExample():String {
    //Your Logic
   }

希望这会有所帮助。