我想在同一协程的动态代理中继续执行暂停功能。 请看下面的代码:
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。 像这样:
val IH = InvocationHandler { _, _, _ ->
delay(5_000)
3
}
这显然不会编译,因为delay是必须在协程中运行的暂停函数。 所以问题是:如何为预期的行为编写InvocationHandler? 任何帮助将不胜感激。
我想在我的RPC框架中使用此代码。 我的真实代码将用无阻塞的Ktor套接字调用代替延迟调用,以通过网络串行化数据。 您可以在以下位置找到代码示例:https://raw.githubusercontent.com/softappeal/yass/master/kotlin/yass/test/ch/softappeal/yass/remote/SuspendProxy.kt
答案 0 :(得分:0)
在runBlocking
内使用InvocationHandler
:
val IH = InvocationHandler { _, _, _ ->
runBlocking{
delay(5_000)// now you can use suspend functions here
}
3
}
答案 1 :(得分:0)
我已经找到解决问题的方法:
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
库中?