如何让Java 8 Nashorn速度更快?

内容来源于 Stack Overflow,并遵循CC BY-SA 3.0许可协议进行翻译与使用

  • 回答 (2)
  • 关注 (0)
  • 查看 (25)

我使用Java 8 Nashorn将CommonMark呈现给HTML服务器端。如果我编译并缓存并重用a CompiledScript,则某个页面需要5分钟才能呈现。但是,如果我使用eval并缓存并重新使用脚本引擎,则渲染同一页面需要3秒。

为什么CompiledScript这么慢?(示例代码如下)

尽可能快地在Nashorn中一遍又一遍运行Javascript代码的好方法是什么?并避免不止一次编译Javascript代码?

这是服务器端的Scala代码片段,它需要5分钟的时间来调用Nashorn:(运行200次;我将CommonMark的许多评论编译为HTML。)

if (engine == null) {
  val script = scala.io.Source.fromFile("public/res/remarkable.min.js").mkString
  engine = new js.ScriptEngineManager(null).getEngineByName("nashorn")
  compiledScript = engine.asInstanceOf[js.Compilable].compile(s"""
    var global = this;
    $script;
    remarkable = new Remarkable({});
    remarkable.render(__source__);""");
}
engine.put("__source__", "**bold**")
val htmlText = compiledScript.eval()

请注意,$script以上是重新评估200次。我测试了一次只评估一次的版本,但显然后来我写了一些bug,因为唯一一次版本不会超过5分钟,尽管它应该是最快的版本之一,请参阅Halfbit的答案。这里是快速版本:

...
val newCompiledScript = newEngine.asInstanceOf[js.Compilable].compile(s"""
  var global;
  var remarkable;
  if (!remarkable) {
    global = this;
    $script;
    remarkable = new Remarkable({});
  }
  remarkable.render(__source__);""")
...

而这需要2.7秒:(当运行200次时)

if (engine == null) {
  engine = new js.ScriptEngineManager(null).getEngineByName("nashorn")
  engine.eval("var global = this;")
  engine.eval(new jio.FileReader("public/res/remarkable.min.js"))
  engine.eval("remarkable = new Remarkable({});")
}
engine.put("source", "**bold**")
val htmlText = engine.eval("remarkable.render(source)")

我实际上已经猜到,CompiledScript版本(最顶端的代码片段)会更快。无论如何,我想我必须缓存呈现的HTML服务器端。

(Linux Mint 17和Java 8 u20)

我只注意到,invokeFunction在最后使用而不是eval几乎两倍的速度,只需要1.7秒。这与使用由Rhino编译为Java字节码的Java代码的Java 7版本(作为构建过程中单独和复杂的步骤)大致相同。也许这是尽可能快的速度?

if (engine == null) {
  engine = new js.ScriptEngineManager(null).getEngineByName("nashorn")
  engine.eval("var global = this;")
  engine.eval(new jio.FileReader("public/res/remarkable.min.js"))
  engine.eval("remarkable = new Remarkable({});")
  engine.eval(
    "function renderCommonMark(source) { return remarkable.render(source); }")
}
val htmlText = engine.asInstanceOf[js.Invocable].invokeFunction(
                                       "renderCommonMark", "**bold1**")
提问于
用户回答回答于

您所使用的代码版本CompiledScript似乎重新评估了remarkable.min.js200次 - 而您的eval基础版本则只执行一次。这解释了运行时间的巨大差异。

只需在remarkable.render(__source__)预编译时,CompiledScript基于变种比略快evalinvokeFunction基础的人(我的机器上,甲骨文的Java 8u25上)。

用户回答回答于

扫码关注云+社区