Ich habe nach Dolmetschern / Compilern gesucht und bin dann auf JIT-Compilation gestoßen - speziell auf die V8 Javascript Engine von Google Chrome.
Meine Fragen sind -
- Wie kann es schneller sein als die Standardinterpretation?
- Warum wurde JIT-Compilation überhaupt nicht verwendet?
Mein aktuelles Verständnis
Jedes Javascript-Programm startet als Quellcode und wird dann, unabhängig von der Ausführungsmethode, letztendlich in Maschinencode übersetzt .
Sowohl die JIT-Kompilierung als auch die Interpretation müssen diesem Pfad folgen. Wie kann die JIT-Kompilierung also schneller sein (auch weil die JIT im Gegensatz zur AOT-Kompilierung zeitlich begrenzt ist)?JIT-Compilation scheint eine relativ alte Innovation zu sein , die auf dem JIT-Compilation-Artikel von Wikipedia basiert .
"Der früheste veröffentlichte JIT-Compiler wird in der Regel 1960 von McCarthy auf LISP zurückgeführt ."
"Smalltalk (ca. 1983 ) war ein Pionier bei neuen Aspekten der JIT-Kompilierung. Beispielsweise wurde die Übersetzung in Maschinencode auf Anforderung durchgeführt und das Ergebnis für die spätere Verwendung zwischengespeichert. Wenn der Speicher knapp wurde, löschte das System einen Teil dieses Codes und regenerierte ihn es, wenn es wieder gebraucht wurde. "
Warum also wurde Javascript Ausgelegt mit zu beginnen ?
Ich bin sehr verwirrt und habe viel recherchiert, aber keine zufriedenstellenden Antworten gefunden.
Wir würden uns über klare, prägnante Antworten freuen. Und wenn zusätzliche Erklärungen zu Dolmetschern, JIT-Compilern usw. eingeholt werden müssen, ist dies ebenfalls willkommen.
quelle
Antworten:
Die kurze Antwort lautet: JIT hat längere Initialisierungszeiten, ist aber auf lange Sicht viel schneller, und JavaScript war ursprünglich nicht für die langfristige Verwendung gedacht.
In den 90er Jahren umfasste typisches JavaScript auf einer Website ein oder zwei Funktionen im Header und eine Handvoll Code, der direkt in
onclick
Eigenschaften und dergleichen eingebettet war . Normalerweise wird es richtig ausgeführt, wenn der Benutzer ohnehin eine große Verzögerung beim Laden der Seite erwartet. Denken Sie an eine extrem einfache Formularvalidierung oder an winzige mathematische Hilfsmittel wie Hypothekenzinsrechner.Das Dolmetschen nach Bedarf war viel einfacher und lieferte für die Anwendungsfälle des Tages eine vollkommen adäquate Leistung. Wenn Sie etwas mit langfristiger Leistung möchten, verwenden Sie Flash oder ein Java-Applet.
Google Maps war 2004 eine der ersten Killer-Apps für den intensiven Einsatz von JavaScript. Es öffnete die Augen für die Möglichkeiten von JavaScript, hob aber auch seine Leistungsprobleme hervor. Google verbrachte einige Zeit damit, die Browser zu ermutigen, ihre JavaScript-Leistung zu verbessern, und entschied dann schließlich, dass der Wettbewerb der beste Motivator sein und ihnen den besten Platz am Tisch mit den Browserstandards einräumen würde. Chrome und V8 wurden als Ergebnis im Jahr 2008 veröffentlicht. Jetzt, elf Jahre nach dem Erscheinen von Google Maps, gibt es neue Entwickler, die sich nicht erinnern können, dass JavaScript jemals für eine solche Aufgabe als unzureichend eingestuft wurde.
Angenommen, Sie haben eine Funktion
animateDraggedMap
. Es kann 500 ms dauern, um es zu interpretieren, und 700 ms, um es mit JIT zu kompilieren. Nach der JIT-Kompilierung kann die tatsächliche Ausführung jedoch nur 100 ms dauern. Wenn es die 90er Jahre sind und Sie eine Funktion nur einmal aufrufen und dann die Seite neu laden, lohnt sich JIT überhaupt nicht. Wenn es heute ist und SieanimateDraggedMap
hunderte oder tausende Male anrufen , sind diese zusätzlichen 200 ms bei der Initialisierung nichts und können hinter den Kulissen durchgeführt werden, bevor der Benutzer überhaupt versucht, die Karte zu ziehen.quelle
Wenn Sie wissen, was zur Laufzeit vor sich geht, können Sie Änderungen am Code oder an der Interpretation des Codes vornehmen, die eine schnellere Ausführung oder eine bessere Kompilierung ermöglichen, als dies zum Zeitpunkt der Kompilierung im Voraus bekannt war.
Hierzu ist einiges zu sagen - es ist Gegenstand erheblicher Forschungsarbeiten. Meine eigene Erklärung hier, dass ich anfing, im Vergleich zu der Antwort in Die Unterschiede verstehen blass zu schreiben : traditioneller Interpreter, JIT-Compiler, JIT-Interpreter und AOT-Compiler
Ganz einfach, JavaScript wurde ursprünglich nicht für JIT kompiliert oder geprüft, da es nie so komplex oder wichtig sein sollte.
Die ursprüngliche Absicht von Java Script bestand darin, auf einer Webseite eine Verknüpfung zu Java-Applets herzustellen. Die Möglichkeit, auf eine Schaltfläche zu klicken oder einen Wert in ein Formularfeld einzugeben und anschließend in einer Java-Applet-Methode zu arbeiten, wird unter Aufrufen von Applet-Methoden aus JavaScript-Code angezeigt . Durch JavaScript war es auch möglich, JavaScript-Code von einem Applet aus anders aufzurufen .
Die ursprüngliche Absicht von JavaScript bestand darin, Applets und die darin enthaltenen HTML-Seiten zu verknüpfen. Für solch eine kleine Aufgabe braucht man keine große Leistung (wenn Sie Leistung wünschen, rufen Sie die Applet-Methode auf, die JIT'ed ist).
Erst nachdem Netscape damit begonnen hatte, JavaScript als eigene Sprache zu verwenden und für die Entwicklung zu werben (einschließlich serverseitigem JavaScript auf dem Netscape Enterprise Server, das übrigens vor der Kompilierung erstellt wurde), wurde JavaScript als ernstes Ziel erkannt . Danach dauerte es viele Jahre, bis die erforderlichen Tools zum Einsatz kamen.
quelle
JITs sind für JavaScript schnell, da es unmöglich ist, schnellen Maschinencode zu generieren, wenn Sie den Typ Ihrer Variablen nicht kennen.
Wenn Sie keine Typinformationen haben, sind Berechnungen teuer. Beispielsweise,
x + y
ist ziemlich kompliziert, wenn man nichts über x und y weiß. Dies können ganze Zahlen, doppelte Zahlen, Zeichenfolgen oder sogar Objekte sein, bei denen diese Berechnung Nebenwirkungen hat. Da wir keine statische Typisierung haben, ist dies eine teure Berechnung.
Mit der Just-in-Time-Kompilierung können wir Laufzeitinformationen verwenden und diese in eine schnellere Berechnung umwandeln. Zur Laufzeit verfolgt V8 den Variablentyp. Wenn der obige Code mehrmals mit beispielsweise Zeichenfolgen ausgeführt wird, kann der Compiler die wesentlich einfacheren Anweisungen für die Zeichenfolgenverkettung ausführen. Wenn der Compiler erreicht
x + y
, prüft der Compiler schnell, ob es erneut Zeichenfolgen gibt, und führt dann nur einige Zeilen Maschinencode aus, die speziell Zeichenfolgen verketten, anstatt viel Code auszuführen, der für viele verschiedene Typen von x und y verzweigt.In C ++ kennt der Compiler die Typen von x und y im Voraus, da wir die Variablen deklarieren mussten. So kann optimierter Maschinencode zum Verketten von Zeichenfolgen generiert werden, bevor der Code ausgeführt wird.
quelle
1) Wie kann es schneller sein als die Standardinterpretation? Nun, ein ausgedachtes Beispiel wäre wie folgt; Angenommen, wir haben 2 Anwendungen ApplicationCompiled und ApplicationInterpreted. Beide Programme tun genau dasselbe und verwenden denselben Quellcode. Das Kompilieren von ApplicationCompiled dauert 6 Sekunden.
Nehmen wir an, das Timing von Szenario A ist:
Insgesamt benötigt ApplicationCompiled 10 Sekunden für die Ausführung von Szenario A (6 Sekunden für die Kompilierung, 4 Sekunden für die Ausführung) und ApplicationInterpreted insgesamt 12 Sekunden für die Ausführung. Ich habe kein konkretes Beispiel, um es Ihnen zu zeigen, und ich bin nicht sicher, unter welchen Fällen das oben Genannte zutrifft - es hängt auch stark davon ab, wie intelligent die Interpretation und der Compiler sind.
Offensichtlich ist dies sehr vereinfacht, aber imho die gleiche Idee kann auf das Kompilieren / Interpretieren von JIT angewendet werden. Die nächste Frage wäre dann: "Wie bestimmen wir mit geringen Kosten, ob dieser Zweig JIT-kompiliert oder interpretiert werden soll?" Ich bin hier nicht in meiner Liga :)
2) Warum wurde JIT-Compilation überhaupt nicht verwendet? Ich weiß es nicht, aber ich denke, es ist einfach eine Frage der Ressourcen und des Reifegrads des verfügbaren Fortschritts bei der Entwicklung einer schwer zu optimierenden Sprache wie JavaScript, um fortschrittliche Techniken wie diese anzuwenden. Zu der Zeit gab es wahrscheinlich viele niedrig hängende Früchte.
quelle