首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >问答首页 >如何在同一协程中继续动态代理中的挂起功能?

如何在同一协程中继续动态代理中的挂起功能?
EN

Stack Overflow用户
提问于 2019-02-01 03:03:30
回答 2查看 285关注 0票数 0

我想在同一协程中继续动态代理中的挂起功能。请看下面的代码:

代码语言:javascript
运行
复制
interface Adder {
    suspend fun add(a: Int, b: Int): Int
}

val IH = InvocationHandler { _, method, args ->
    val continuation = args.last() as Continuation<*>
    val realArgs = args.take(args.size - 1)
    println("${method.name}$realArgs")
    GlobalScope.launch {
        delay(5_000)
        @Suppress("UNCHECKED_CAST") (continuation as Continuation<Int>).resume(3)
    }
    COROUTINE_SUSPENDED
}

fun main() {
    val adder = Proxy.newProxyInstance(
        Adder::class.java.classLoader, arrayOf(Adder::class.java), IH
    ) as Adder
    runBlocking {
        println(adder.add(1, 2))
    }
}

它工作得很好。它在一个新的协程中运行延迟函数。然而,这不是我想要的。

我想在与runBlocking启动时相同的协程中运行InvocationHandler。类似于:

代码语言:javascript
运行
复制
val IH = InvocationHandler { _, _, _ ->
    delay(5_000)
    3
}

这显然无法编译,因为延迟是一个必须在协程中运行的挂起函数。所以问题是:我如何才能为我的预期行为编写InvocationHandler?任何帮助都将不胜感激。

我想在我的RPC框架中使用这段代码。我的实际代码将使用非阻塞Ktor套接字调用替换延迟调用,以便通过网络序列化数据。您可以在https://raw.githubusercontent.com/softappeal/yass/master/kotlin/yass/test/ch/softappeal/yass/remote/SuspendProxy.kt中找到代码示例

EN

回答 2

Stack Overflow用户

发布于 2019-02-02 22:58:28

我已经为我的问题找到了解决方案:

代码语言:javascript
运行
复制
package ch.softappeal.yass

import kotlinx.coroutines.*
import java.lang.reflect.*
import kotlin.coroutines.*
import kotlin.test.*

typealias SuspendInvoker = suspend (method: Method, arguments: List<Any?>) -> Any?

private interface SuspendFunction {
    suspend fun invoke(): Any?
}

private val SuspendRemover = SuspendFunction::class.java.methods[0]

@Suppress("UNCHECKED_CAST")
fun <C : Any> proxy(contract: Class<C>, invoker: SuspendInvoker): C =
    Proxy.newProxyInstance(contract.classLoader, arrayOf(contract)) { _, method, arguments ->
        val continuation = arguments.last() as Continuation<*>
        val argumentsWithoutContinuation = arguments.take(arguments.size - 1)
        SuspendRemover.invoke(object : SuspendFunction {
            override suspend fun invoke() = invoker(method, argumentsWithoutContinuation)
        }, continuation)
    } as C

interface Adder {
    suspend fun add(a: Int, b: Int): Int
}

class SuspendProxyTest {
    @Test
    fun test() {
        val adder = proxy(Adder::class.java) { method, arguments ->
            println("${method.name}$arguments")
            delay(100)
            3
        }
        runBlocking { assertEquals(3, adder.add(1, 2)) }
    }
}

有什么意见吗?

这是一个好的/有问题的解决方案吗?

可以/应该将“删除挂起功能”添加到kotlin.coroutines库中吗?

票数 1
EN

Stack Overflow用户

发布于 2019-02-01 06:07:36

InvocationHandler中使用runBlocking

代码语言:javascript
运行
复制
val IH = InvocationHandler { _, _, _ ->

    runBlocking{
        delay(5_000)// now you can use suspend functions here
    }

    3
}
票数 0
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/54467556

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档