Sto usando Java 8 Nashorn per il rendering di CommonMark lato server HTML. Se compilo e cache e riusci uno CompiledScript
, una determinata pagina impiega 5 minuti per il rendering. Tuttavia, se invece utilizzo eval
e cache e riutilizza il motore di script, il rendering della stessa pagina richiede 3 secondi.Come rendere veloce Java 8 Nashorn?
Perché lo è CompiledScript
così lento? (segue il codice di esempio)
Qual è un buon approccio per l'esecuzione del codice Javascript in Nashorn, più e più volte il più rapidamente possibile? E evitando di compilare il codice Javascript più di una volta?
Questo è lo snippet di codice Scala lato server che chiama Nashorn in un modo che richiede 5 minuti: (quando viene eseguito 200 volte, sto compilando molti commenti da CommonMark a HTML.) (Questo codice è basato su this blog article.)
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()
Modifica si noti che il $script
sopra si rivaluta 200 volte. Ho provato una versione che l'ha valutata solo una volta, ma a quanto pare ho scritto qualche bug, perché la versione solo una volta non era più veloce di 5 minuti, anche se avrebbe dovuto essere uno dei più veloci, see Halfbit's answer. Ecco la versione veloce:
...
val newCompiledScript = newEngine.asInstanceOf[js.Compilable].compile(s"""
var global;
var remarkable;
if (!remarkable) {
global = this;
$script;
remarkable = new Remarkable({});
}
remarkable.render(__source__);""")
...
/Modifica
considerando che la presente richiede 2,7 secondi: (quando viene eseguito 200 volte)
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)")
vorrei davvero hanno intuito che la versione CompiledScript
(la il frammento più in alto) sarebbe stato più veloce. Ad ogni modo, suppongo che dovrò mettere in cache il lato del server HTML reso.
(Linux Mint 17 & Java 8 U20)
Aggiornamento:
Ho appena notato che usando invokeFunction
alla fine, invece di eval
è quasi due volte più veloce, richiede solo 1,7 secondi. Questo è più o meno veloce della mia versione di Java 7 che utilizzava il codice Javascript compilato da Rhino in bytecode Java (come un passaggio separato e complicato nel processo di compilazione). Forse questo è il più veloce che può arrivare?
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**")
Ho anche trovato che Nashorn è più lento del rhino http://softwarecenturion.me/posts/2014-04-07-jdk8-nashorn-performance/. Diventa molto più veloce con JIT caldo, ma è freddo insolitamente lento. Anche curioso se c'è qualcosa che puoi fare al riguardo. – coudy