尝试调用运行阻塞时,Kotlin Vertex与协程阻塞
我正在使用一个第三方库,它公开了一个回调函数。成功后将调用回调函数。回调函数不是挂起函数,但当我尝试在非挂起函数中进行调用以返回挂起函数的结果时(该函数使用aysnc和WAIT进行IO调用),调用永远不会被强制执行。下面我给出了一个简单的代码片段来演示这个问题尝试调用运行阻塞时,Kotlin Vertex与协程阻塞,kotlin,vert.x,kotlin-coroutines,vertx-verticle,Kotlin,Vert.x,Kotlin Coroutines,Vertx Verticle,我正在使用一个第三方库,它公开了一个回调函数。成功后将调用回调函数。回调函数不是挂起函数,但当我尝试在非挂起函数中进行调用以返回挂起函数的结果时(该函数使用aysnc和WAIT进行IO调用),调用永远不会被强制执行。下面我给出了一个简单的代码片段来演示这个问题 open class TestVerticle: CoroutineVerticle() { override suspend fun start() { awaitBlockingExample() } fun
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")
}
开放类TestVerticle:CoroutineVerticle(){
覆盖暂停乐趣开始(){
waitingblockingexample()
}
示例():字符串{
val future=async(vertx.dispatcher()){
makeSuspendFunCall()
}
val结果:String=runBlocking(vertx.dispatcher()){future.await()}
println(“最终结果为$Result”)
返回结果
}
suspend fun makeSuspendFunCall():字符串{
println(“此处提交3”)
延迟(500)
val resp=“测试”
返回响应
}
}
fun main(args:Array)=运行阻塞{
Vertx.Vertx().deployVerticle(“TestVerticle”)
}
如果我删除makeSuspendFunCall中的延迟函数,程序将运行,但如果我添加延迟函数,程序将挂起。我实际上是在用延迟函数模拟挂起函数网络调用。在这种情况下,如何从WaitingBlockingExample中获得结果?我清楚地理解,通过将waitingblockingexample作为suspend函数,我可以实现这一点,并删除其中的异步和运行阻塞调用。但在这里,WaitingBlockingExample(非挂起函数)表示一个由this party库提供的实现,它在我们的实现中被重写。例如,guava cache提供了一个重载函数,我想重写重载函数(非挂起函数)并从重载方法调用一个协程函数,以从数据库或网络调用中刷新缓存值。问题在于
vertx.dispatcher()
使用单个线程作为事件循环,并运行阻塞
阻塞此线程
详情:
您的waitingblockingexample()
函数正在这个Vertx事件循环线程上运行,因为它是从suspend start()函数触发的。如果调用runBlocking()
此Vertx线程将被阻止,并且永远不会释放。但是您的其他协同程序,例如async()
,现在没有线程来执行它们的工作
解决方案:
我假设从start
函数调用waitingblockingexample
仅在本例中发生。实际上,我假设外部回调使用自己的线程。那么就没有问题了,因为现在外部线程被阻塞了:
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()
块,您可以从runBlocking()
尝试下一种方法:
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)
}
}
适用于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
}
希望这会有所帮助。正如我在问题中提到的,我特别想寻找一种解决方案,解决如何从非挂起函数调用协程IO阻塞调用的问题。我只是在代码片段中简化了我的用例。例如,guava cache提供了一个重载函数,我想重写重载函数(非挂起函数)并从重载方法调用一个协程函数,以从数据库或网络调用中刷新缓存值。我们也不能使用SuspendCorroutine,因为重载方法不是suspend函数,在SuspendCorroutine内部,我们不能调用Corroutine函数。从未挂起的函数调用挂起的函数总是阻塞的。您可以使用runBlocking
。@sedovav如果您看到我在问题中使用run blocking,那么当我从非挂起函数调用挂起函数并调用挂起函数时,我的问题是调用另一个挂起函数(在问题延迟函数中),整个线程都会被阻塞,应用程序永远不会recovers@DevLoper我已经改变了我的答案,希望它现在更好。@Rene现在的答案是解决我讨论的问题,但它并没有完全解决它。如果我使用您的解决方案,我会在线程“main”io.vertx.core.VertxException中遇到以下错误异常:从错误的线程执行。找不到ForkJoinPool.commonPool-worker-1的上下文。这是因为suspend函数使用vertx提供的httpclient,而默认dispatcher没有vertx上下文。您使用的是哪个kotlin版本?
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
}