Nashorn Ineffizienz

8

Ich implementiere leistungsabhängigen Code mit Nashorn. Ich mache es so:

%Vor%

Zur Laufzeit besteht Nashorn darauf, viele notwendige Aufrufe an MyScriptContext vorzunehmen. Es besteht darauf, bei jedem Aufruf von eval () MyScriptContext.getBindings (). Put ("nashorn.global", anObject) aufzurufen. Dann ruft er MyScriptContext.getAttribute ("someVariable") auf (was er sollte) und ruft MyScriptContext.getAttribute ("someFunction") auf (was nicht sein sollte).

Der Aufruf von "someFunction ()" sollte nicht erfolgen, da diese Funktion zur Kompilierzeit verfügbar war. "someFunction ()" muss zum Kompilierungszeitpunkt in kompilierte Bytecode kompiliert werden und nicht bei jedem Aufruf von eval (). eval () befindet sich in einer engen Schleife.

Wie überzeuge ich Nashorn, weniger Aufrufe von MyScriptContext vorzunehmen?

    
ccleve 15.12.2014, 22:13
quelle

1 Antwort

32

Nashorn muss jede global definierte Variable (einschließlich global definierter Funktionen) im Kontext nachschlagen, da die Globals extern neu definiert werden können und es keine Möglichkeit gibt zu wissen, dass sie nicht neu definiert werden. Daher können wir eine Funktion niemals in Bytecode vorzeitig binden. Ich werde mehrere Ansätze zur Verbesserung der Leistung skizzieren.

Umschließen Sie Ihren Code in einem sofort aufgerufenen anonymen Funktionsausdruck

Sie könnten die Leistung verbessern, indem Sie Ihr Programm in einer anonymen Funktion definieren und es damit zu einem nicht-globalen Bereich machen:

%Vor%

In diesem Fall können Funktionsobjekte innerhalb der anonymen Funktion in lokalen Bytecode-Variablen gespeichert werden.

Reduziere die Abhängigkeit von Globalen, indem du sie als Parameter übergibst

Wenn Ihr Code leistungsabhängig ist, sollten Sie die Verwendung von Globals generell minimieren. 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 von den globalen x und y abhängt, tun Sie Folgendes:

%Vor%

Offensichtlich funktioniert das 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 benutze, wenn ich nur vom globalen lexikalischen Kontext in einen privaten lebe).

Verwenden Sie die äußere anonyme Funktion, um den Code zu halten, und eine weitere für Auswertungen

Eigentlich können Sie es 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 Wenn Sie den lexikalischen Geltungsbereich Ihrer Anon-Funktion unveränderlich machen können, können Sie sie einfach einmal erstellen und eine Funktion von ihr zurückgeben, die alle anderen in ihrem eigenen Geltungsbereich sieht:

%Vor%

(An dieser Stelle müssen Sie nicht einmal CompiledScript von Java verwenden, aber ich schlage vor, dass Sie tun, wenn Sie Ihre Absicht der Engine mitteilen, dass eine Repräsentation für die wiederholte Auswertung optimiert werden soll).

Ab Java können Sie nun script.eval() gefolgt von JSObject program = (JSObject)context.get("program") ausführen und anschließend beliebig oft mit program.call(null, x, y) aufrufen. ( JSObject ist Nashorns Java-Interface für native Objekte, sowohl normale als auch Funktionen).

Alternativ können Sie ein anderes Skript mit engine.compile("program(x, y)" für den Aufruf erstellen und sicherstellen, dass x und y in den Kontext eingefügt werden, bevor eval() ing wird.

Sie werden bei wiederholter Auswertung auf diese Weise am meisten abnehmen. 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. Sie sollten jedoch auch darauf achten, dass sie auch gemeinsam genutzt werden, wenn Sie einen änderbaren Status (einige var s im Funktionsumfang) haben.

    
Attila Szegedi 19.12.2014, 08:30
quelle

Tags und Links