PMV hat geschrieben:edel hat geschrieben:Aber du wirst keinen Unterschied zur Laufzeit bemerken.
Also wenn ich ein Programm schreibe, das ...
... ganz oder zum teil interpretiert wird,
... zur Laufzeit sämtliche Variablen überwacht
... keine direkte Speichermanipulation erlaubt
Wie soll das genau so schneller sein wie ein Programm, das ...
... in Maschinensprache des Prozessors vor liegt
... keine Überwachung voraussetzt
... direkt effizient Speicher bearbeitet
Bitte erklär mir das. Eine Aussage ala "das geht" ist genau so hilfreich wie,
"das geht nicht".
Da müssen wir doch erst einmal dazu sagen, dass PB kaum den Code
optimiert. Wirklich. Die "grossen" Compiler anderer Sprachen haben da
weit aufwändigere und effektivere Optimierungen parat.
Deshalb möchte ich deine Frage mal inklusive der Vorstellung erklären, PB
würde guten Code generieren.
1. Die langsame Startzeit von Java und C# ist unnötig. Verwendet man eine
Kombination von Interpreter und JIT, kann man ohne Probleme _sofort_
per Interpreter starten und das Programm dann per JIT in einer ruhigen
Phase kompilieren. Aber klar, das verteilt diesen Overhead.
2. Der Teil der Laufzeit, in dem in deinem Programm "Variablen überwacht"
werden, ist gering. Der Rest kann so optimiert werden, dass das nicht
mehr nötig ist. Stell dir mal vor, du hast eine Funktion, welche ein Bild
verarbeitet und komprimiert. Wenn der Compiler weiss, dass sowieso nichts
dazwischen funken kann, wird er diese "Überwachung" einfach ausschalten
und diese Funktion wie ein effizienter C-Compiler optimieren. Das geht bei
den meisten rechenintensiven Funktionen, wenn sie richtig programmiert
sind.
3. Nun zur eigentlichen Erklärung, warum JIT+Interpreter schneller sein
kann als selbst gut optimierter Code:
Es gibt viele effektive Techniken zu "Runtime Optimizations" oder "JIT
Optimizations". Zum Einen erlauben es solche Optimierungen, direkt auf
den verwendeten Prozessor zu kompilieren (anstatt generisch für alle
Möglichen) und zum Anderen führen JIT-Compiler zur Laufzeit Statistiken
mit. Beispielsweise wie oft eine Funktion aufgerufen wird -> Kandidat zum
inlinen, wie oft dieser Speicherbereich genutzt wird -> schiebe ihn in den
CPU-Cache, wie das "Access-Pattern" im Speicher aussieht -> führe
verschiedene Speicherbereiche zusammen (besseres CPU-Caching), wie
oft wird das ELSE eines IFs ausgeführt -> helfe der CPU-Branch-Prediction
oder welche Funktionen dieser _dynamisch_ geladenen Bibliothek werden
immer wieder verwendet -> Inlining oder sonst die Code-Lokalität erhöhen.
Das sind nur einige der vielen Optimierungsmöglichkeiten, welche erst durch
Bytecode+Interpreter+JIT möglich werden.
greetz
Remi
tl;dr... was edel sagt, nur länger
Edit:
http://www.javaperformancetuning.com/news/qotm042.shtml