如何使Java 8 Nashorn快速?

 robinqianqcs521 发布于 2022-12-15 14:00

我正在使用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编译的Javascript代码到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**")

halfbit.. 8

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

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

撰写答案
今天,你开发时遇到什么问题呢?
立即提问
热门标签
PHP1.CN | 中国最专业的PHP中文社区 | PNG素材下载 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有