Używam Java 8 Nashorn do renderowania CommonMark po stronie serwera HTML. Jeśli kompiluję i buforuję i ponownie używam CompiledScript
, pewna strona zajmuje 5 minut. Jednakże, jeśli zamiast tego użyję eval
, i buforowania i ponownego użycia silnika skryptu, renderowanie tej samej strony trwa 3 sekundy.Jak szybko zrobić Java 8 Nashorn?
Dlaczego tak wolny jest CompiledScript
? (przykładowy kod jest podany)
Jakie jest dobre podejście do uruchamiania kodu JavaScript w Nashorn tak szybko, jak to możliwe? I unikanie kompilowania kodu Javascript więcej niż raz?
To jest fragment kodu Scala po stronie serwera, który wywołuje Nashorn w sposób trwający 5 minut: (gdy uruchamiam 200 razy, kompiluję wiele komentarzy od CommonMark do HTML.) (Ten kod jest oparty na 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()
Edit Należy zauważyć, że powyższe $script
jest reevaluated 200 razy. Testowałem wersję, która oceniła ją tylko raz, ale najwyraźniej napisałem jakiś błąd, ponieważ jedyna wersja nie była szybsza niż 5 minut, chociaż powinna być jedną z najszybszych, see Halfbit's answer. Oto szybka wersja:
...
val newCompiledScript = newEngine.asInstanceOf[js.Compilable].compile(s"""
var global;
var remarkable;
if (!remarkable) {
global = this;
$script;
remarkable = new Remarkable({});
}
remarkable.render(__source__);""")
...
/Edycja
niniejsza trwa 2,7 sekundy (w przypadku uruchomienia 200 razy)
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)")
I rzeczywiście się domyślić, że wersja CompiledScript
(the najwyższy fragment) byłaby szybsza. W każdym razie, przypuszczam, że będę musiał buforować stronę renderowanego serwera HTML.
(Linux Mint 17 & Java 8 u20)
Aktualizacja:
Właśnie zauważyłem, że przy użyciu invokeFunction
na końcu zamiast eval
jest prawie dwa razy szybciej, zajmuje tylko 1,7 sekundy. Jest to mniej więcej tak szybkie, jak moja wersja Java 7, która wykorzystywała kod JavaScript skompilowany przez Rhino do kodu bajtowego Java (jako osobny i skomplikowany krok w procesie kompilacji). Być może jest to tak szybko, jak to możliwe?
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**")
Znalazłem również nashorn wolniej niż rhino http://softwarecenturion.me/posts/2014-04-07-jdk8-nashorn-performance/. Staje się znacznie szybszy przy ciepłym JIT, ale jest wyjątkowo powolny na zimno. Ciekawe, czy jest coś, co możesz z tym zrobić. – coudy