GroovyShell 线程安全
GroovyShell Thread safety
该问题出现在所有关于 GroovyShell 的问题的评论中,例如 Using GroovyShell as "expression evaluator/engine" (or: How to reuse GroovyShell)。不足为奇,因为 API 的设计似乎根本没有涵盖这个主题。不幸的是,这从未被明确讨论过。
紧凑形式的问题:
静态初始化:
final GroovyShell shell = new GroovyShell();
final Script thisScript = shell.parse("sleep 1000; return input1+' '+input2");
//anotherScript = // not relevant here but my use-case pre-loads ~300 groovy scripts
脚本运行程序:
private Object runScript(Script theScript, String param1, String param2) {
theScript.setProperty("input1", param1);
theScript.setProperty("input2", param2);
Object result = theScript.run();
return result;
}
序列化执行:
runScript(thisScript, "Hello", "World") -> Hello World
runScript(thisScript, "Guten", "Tag") -> Guten Tag
并行执行:
runScript(thisScript, "Hello", "World") -> Guten Tag (!)
runScript(thisScript, "Guten", "Tag") -> Guten Tag
问题是绑定(无论 get/setBinding 还是 setProperty)是在脚本级别完成的。这就像在通过 classLoader 加载对象或修改静态成员变量后在加载的 java.lang.Class 对象上设置一些东西。是否有替代 groovy 实现来处理绑定和 运行 作为原子操作?或者更好:使用上下文对象执行?
最简单的解决方法是将 runScript()
同步到脚本对象,但这无法扩展。
并行创建脚本的不同实例 class 到 运行。
GroovyShell shell = new GroovyShell();
Class<Script> scriptClass = shell.parse("sleep 1000; return input1+' '+input2").getClass();
Object runScript(Class<Script> clazz, String param1, String param2) {
Script theScript = clazz.newInstance();
theScript.setProperty("input1", param1);
theScript.setProperty("input2", param2);
Object result = theScript.run();
return result;
}
//thread test
[
["111","aaa"],
["222","bbb"]
].collect{x->
Thread.start{
println "start $x"
println runScript(scriptClass, x[0], x[1])
}
}*.join()
输出:
start [111, aaa]
start [222, bbb]
111 aaa
222 bbb
该问题出现在所有关于 GroovyShell 的问题的评论中,例如 Using GroovyShell as "expression evaluator/engine" (or: How to reuse GroovyShell)。不足为奇,因为 API 的设计似乎根本没有涵盖这个主题。不幸的是,这从未被明确讨论过。
紧凑形式的问题:
静态初始化:
final GroovyShell shell = new GroovyShell();
final Script thisScript = shell.parse("sleep 1000; return input1+' '+input2");
//anotherScript = // not relevant here but my use-case pre-loads ~300 groovy scripts
脚本运行程序:
private Object runScript(Script theScript, String param1, String param2) {
theScript.setProperty("input1", param1);
theScript.setProperty("input2", param2);
Object result = theScript.run();
return result;
}
序列化执行:
runScript(thisScript, "Hello", "World") -> Hello World
runScript(thisScript, "Guten", "Tag") -> Guten Tag
并行执行:
runScript(thisScript, "Hello", "World") -> Guten Tag (!)
runScript(thisScript, "Guten", "Tag") -> Guten Tag
问题是绑定(无论 get/setBinding 还是 setProperty)是在脚本级别完成的。这就像在通过 classLoader 加载对象或修改静态成员变量后在加载的 java.lang.Class 对象上设置一些东西。是否有替代 groovy 实现来处理绑定和 运行 作为原子操作?或者更好:使用上下文对象执行?
最简单的解决方法是将 runScript()
同步到脚本对象,但这无法扩展。
并行创建脚本的不同实例 class 到 运行。
GroovyShell shell = new GroovyShell();
Class<Script> scriptClass = shell.parse("sleep 1000; return input1+' '+input2").getClass();
Object runScript(Class<Script> clazz, String param1, String param2) {
Script theScript = clazz.newInstance();
theScript.setProperty("input1", param1);
theScript.setProperty("input2", param2);
Object result = theScript.run();
return result;
}
//thread test
[
["111","aaa"],
["222","bbb"]
].collect{x->
Thread.start{
println "start $x"
println runScript(scriptClass, x[0], x[1])
}
}*.join()
输出:
start [111, aaa]
start [222, bbb]
111 aaa
222 bbb