【发布时间】:2017-03-01 22:57:05
【问题描述】:
我有一个自制的 ETL 解决方案。转换层在 JavaScript 脚本的配置文件中定义,由 Java 的 Nashorn 引擎解释。
我遇到了性能问题。也许没有什么可以做的,但我希望有人能找到我使用 Nashorn 的方式有帮助的问题。该进程是多线程的。
我创建了一个单独的静态 ScriptEngine,它只用于创建 CompiledScript 对象。
private static ScriptEngine engine = new ScriptEngineManager().getEngineByName("JavaScript");
我将在每条记录上重新执行的小脚本编译成 CompiledScript 对象。
public static CompiledScript compile(Reader reader) throws ScriptException {
return ((Compilable) engine).compile(reader);
}
有两个标准的 JavaScript 库也是使用这种方法编译的。
为每条记录创建一个 ScriptContext,添加标准库,并将记录的值设置为绑定。
public static ScriptContext getContext(List<CompiledScript> libs, Map<String, ? extends Object> variables) throws ScriptException {
SimpleScriptContext context = new SimpleScriptContext();
Bindings bindings = context.getBindings(ScriptContext.ENGINE_SCOPE);
for (CompiledScript lib : libs) {
lib.eval(context);
}
for (Entry<String, ? extends Object> variable : variables.entrySet()) {
bindings.put("$" + variable.getKey(), variable.getValue());
}
return context;
}
然后记录的上下文用于转换记录和评估过滤器,所有这些都使用 CompiledScripts。
public static String evalToString(CompiledScript script, ScriptContext context) throws ScriptException {
return script.eval(context).toString();
}
CompiledScripts 对 ScriptContext 的实际执行非常快,但是 ScriptContexts 的初始化非常慢。不幸的是,至少据我了解,这必须针对每组绑定进行。如果记录与过滤器匹配,那么我必须为同一条记录再次重建上下文,这一次使用来自匹配过滤器的一些附加绑定。
每次创建 ScriptContext 时都必须重新执行这两个标准库似乎效率很低,但是我发现在执行这些库之后但在添加绑定之前没有线程安全的方法来克隆 ScriptContext。如果它与过滤器匹配,则必须重新执行两个标准库并重新附加记录中的所有绑定似乎也非常低效,但是我再次发现没有线程安全的方法来克隆记录的 ScriptContext 以将另一个绑定附加到它而不改变原件。
根据jvisualvm,我的程序大部分时间都花在了
jdk.internal.dynalink.support.AbstractRelinkableCallSite.initialize() (70%)
jdk.internal.dynalink.ChainedCallSite.relinkInternal() (14%)
如果对 Nashorn 有任何见解,可以帮助提高此用例的性能,我将不胜感激。谢谢。
【问题讨论】:
标签: java java-8 nashorn scriptengine