Nashorn hat jedes global definierte Variablen (einschließlich global definierte Funktionen) im Kontext zu sehen, wie die Globals extern neu definiert werden können, und es gibt keine Möglichkeit, sie zu kennen, sind nicht neu definiert. Daher können wir eine Funktion niemals in Bytecode vorzeitig binden. Ich werde mehrere Ansätze zur Verbesserung der Leistung skizzieren.
Ihren Code in einer unmittelbar aufgerufen anonyme Funktion Ausdruck Wrap
Sie können die Leistung verbessern, indem Sie Ihr Programm in einer anonymen Funktion zu definieren, damit sie einen nicht-globalen Rahmen zu geben:
(function() {
// put your original code here, like this:
// ...
function someFunction() { ... }
...
someFunction();
...
})();
Darin Fall können Funktionsobjekte innerhalb der anonymen Funktion in lokalen Bytecode-Variablen gespeichert werden.
Abhängigkeit von Globals reduzieren sie, indem Sie sich als
Im allgemeinen Parameter, wenn Ihr Code Leistung empfindlich ist, minimiert die Verwendung von Globals. Wenn Sie globale Variablen verwenden müssen, können Sie sie sogar in Parameter der Funktion verschieben, damit sie dort zu lokalen Variablen werden. Z.B. Wenn Ihr Code auf Globals hängt x
und y
, tun:
(function(x, y) {
// put your original code here, like this:
// ...
function someFunction() { ... }
...
someFunction();
...
})(x, y);
Offensichtlich funktioniert dies nur für Lesezugriff auf Variablen. (Dies funktioniert natürlich mit jeder Funktion, nicht nur mit einem anonymen, sofort aufgerufenen Funktionsausdruck; es ist nur ein Konstrukt, das ich verwende, wenn ich nur vom globalen lexikalischen Kontext in einen privaten lebe).
Verwenden äußere anonyme Funktion den Code und ein anderes für Auswertungen
Eigentlich zu halten, können Sie noch besser machen. Im obigen Beispiel werten Sie immer noch den Körper der anon-Funktion aus und erstellen Funktionsobjekte. (Das ist nicht so schlimm, wohlgemerkt; sie werden nicht erneut kompiliert. Ein Funktionsobjekt ist im Wesentlichen ein Paar Zeiger: eins zum Code, eins zum lexikalischen Bereich und ist schnell zu erstellen. Code wird einmal kompiliert.) Aber in Dann können Sie Ihre Anon-Funktion des lexikalischen Gültigkeitsbereich unveränderlich machen, können Sie es nur einmal erstellen und eine Funktion von ihm zurück, die alle anderen in seinem eigenen Rahmen sehen:
var program = (function() {
// put all your function declarations and other constants here
...
function someFunction() { ... }
...
return new function(x, y) {
// put your original code, minus the function declarations etc. here
...
someFunction();
...
}
})();
(an dieser Stelle, nicht wahr muss sogar CompiledScript
von Java verwenden, aber ich schlage vor, dass Sie tun, wie Sie Ihre Absicht der Maschine mitteilen, dass Sie eine Darstellung wünschen, die für wiederholte Auswertung optimiert wird).
Von Java, jetzt können Sie script.eval()
gefolgt von JSObject program = (JSObject)context.get("program")
tun und anschließend beliebig oft mit program.call(null, x, y)
aufrufen. (JSObject
ist Nashorns Java-Schnittstelle für native Objekte, sowohl normale als auch Funktionen).
Alternativ können Sie auch ein anderes Skript engine.compile("program(x, y)"
für den Aufruf erstellen und stellen Sie sicher, bevor eval()
x
und y
in den Kontext um es ing.
Sie werden die meisten auf wiederholte Auswertung auf diese Weise abgeholzt. Es ist jedoch wichtig zu beachten, dass alle Aufrufe den lexikalischen Umfang des äußersten anonymen Aufrufs gemeinsam haben. Auf diese Weise erhalten Sie die gleichen Funktionsobjekte, ohne sie jemals neu erstellen zu müssen, aber auch, wenn Sie dort einen änderbaren Status haben (einige var
s im Funktionsumfang), werden sie ebenfalls geteilt.
"Ich implementiere Performance-sensitiven Code mit Nashorn" Warum implementieren Sie leistungsempfindliche Dinge in einer Skriptsprache? – Holger
Weil ich muss. Es ist eine grundlegende Anwendungsvoraussetzung. Und ja, es macht Sinn im Zusammenhang mit dieser Anwendung. – ccleve