我在ScriptEngine的KotlinsJSR-223实现中遇到了一些奇怪的问题(kotlin-scripting JSR 223)
基本上,我有一个条件,我解析并编译成一个CompiledScript:
fun parse(clazz: KClass<out GenericEvent>, condition: String): String {
val simpleName = clazz.simpleName
return """
import ${clazz.java.name}
val condition: $simpleName.() -> Boolean = { ${trimQuotes(condition)} }
fun check(event: $simpleName) = condition.invoke(event)
""".trimIndent()
}然后使用(engine as Compilable).compile(code)将结果字符串编译成一个CompiledScript。
现在,每当我尝试在很短的时间内多次eval()这些CompiledScript:
listener.compiledScript.eval()
return@Callable (engine as Invocable).invokeFunction("check", event)它似乎重用了以前使用过的参数。首先,我认为这是一个线程安全问题(因为它看上去很像),但是使用Mutex或单个线程执行程序编译脚本并没有改变这种行为。
完整代码:
override suspend fun onEvent(e: GenericEvent) {
val events = listeners[e.javaClass] ?: return
events.forEach { listener ->
try {
val event = e.javaClass.cast(e)
if (listener.compiledScript != null) {
val result = executor.submit(Callable { // executor = Executors.newSingleThreadExecutor()
println(Thread.currentThread().id) // confirms it's always the same thread
listener.compiledScript.eval()
return@Callable (engine as Invocable).invokeFunction("check", event)
}).get()
if (result is Boolean && result)
listener.method.callSuspend(listener.instance, event)
} else {
listener.method.callSuspend(listener.instance, event)
}
} catch (throwable: Throwable) {
log.error("An error occurred while evaluating listener condition!", throwable)
}
}
}一开始,这是按预期工作的。
Condition: message.contentRaw == "first"
Is actually: first但它创造了奇怪的,但总是相同的模式之后。
Condition: message.contentRaw == "first"
Is actually: second
Condition: message.contentRaw == "second"
Is actually: second
Condition: message.contentRaw == "first"
Is actually: second
Condition: message.contentRaw == "second"
Is actually: second
Condition: message.contentRaw == "first"
Is actually: second
Condition: message.contentRaw == "second"
Is actually: second(如果条件不为真,则不应打印这些消息)
我在前面做了一些调试,在其中我在编译代码本身中打印了条件和实际事件,并且它在check()中重用了前面的事件参数,尽管我实际上在其中使用了一个完全不同的事件参数。
发布于 2022-06-28 19:51:20
通过创建一个新的SimpleScriptContext,将其传递到CompiledScript的eval()方法,然后在调用invokeFunction()之前用新创建的上下文调用ScriptEngine#setContext来修正这个问题。
疯狂的东西!
https://stackoverflow.com/questions/72790632
复制相似问题