burli hat geschrieben:Den Sinn von einer Scriptsprache in einer Scriptsprache verstehe ich eigentlich nicht. Bei IronPython hatte ich mir eigentlich mehr Performance erhofft weil ich dachte Python wird in IML übersetzt und das wird letztendlich nativ compiliert. Aber das war wohl ein Trugschluss. Vielmehr ist wohl der Python Interpreter in C# implementiert
IronPython übersetzt in IL - genau wie Jython, JRuby, Pnuts, Rhino oder Groovy in Java-Bytecode übersetzen. Über den Stand des einfachen Interpreters sind die alle hinaus. Allerdings bringt das weniger als einem lieb ist, da der JIT jeweils gerade mal eben den Nachteil durch die nicht auf die Sprache zugeschnittene VM-Architektur auszugleichen vermag. Ich erwarte eigentlich, dass
MagLev, einem auf einer Smalltalk-VM basierendem Ruby JRuby (und IronRuby) zeigt, wo der Hammer hängt... oder Gemstone-Smalltalk ist richtig schlecht. JVM und VES haben natürlich den Vorteil, dass da 10x mehr Ressourcen in die Entwicklung geflossen sind als bei jeder anderen VM.
JRuby ist ein Spezialfall, da hier der ursprüngliche Ruby-Interpreter so langsam ist, dass fast alles, was man versucht, schneller ist :) Daher gelang es hier, Ruby hinter sich zu lassen. Die Jython-Entwickler werden sich mehr anstrengen müssen, da CPython schon mal grundsätzlich schneller ist. JRuby erkauft sich die schnellere Performance übrigens (genau wie Jython) durch deutlich höheren Speicherverbrauch und eine längere Startphase.
Ansonsten: Eine Scriptsprache ist meist ausdrucksstärker als eine klassische Compiler-Sprache wie C oder Java und das das will man sich bei der Entwicklung von neuen Interpretern zu nutze machen. Hier ist ein Beispiel:
Code: Alles auswählen
for i, r in enumerate(map(lambda n: n * n, range(10))):
print i, r
Übersetze ich das in Java - mal ignorierend, dass ich eigentlich kein "int" benutzen darf, weil Python ja beliebig große Ganzzahlen benutzt und auch ignorierend, dass "int" eigentlich nicht als Spezialisierung erlaubt ist, erhalte ich sowas:
Code: Alles auswählen
public class Test {
public static void main(String[] args) {
Function<int, int> f = new Function<int, int>() {
public int apply(int n) {
return n * n;
}
};
for (Tuple2<int, int> t : Python.enumerate(Python.map(f, Python.range(10)))) {
int i = t.get(0);
int r = t.get(1);
Python.print(i, r);
}
}
}
Die Laufzeit wäre beides mal ähnlich, das Java-Programm macht ja nicht mehr oder weniger als die Python-Version. Tatsächlich würde ich erwarten, dass die Java-Version die Chance hat, schneller zu sein, weil das primitive "*" weniger machen muss, als "operator.mul" bei Python.
Unten stehendes Java-Programm könnte man dabei automatisch aus dem Python-Programm erzeugen - jedenfalls wenn man annimmt, das "int" ausreichend ist und eine ausgefeilte Typanalyse hat, die "Tuple2<int, int>" ermitteln kann.
Hier sind die statischen Funktionen, die ich benutzt habe.
Eine einfachere, aber nicht mehr so effiziente Übersetzung wäre, das statisches Typsystem von Java auszuhebeln und überall mit "PyObject"-Exemplaren zu arbeiten, von denen dann "PyInt" eine Unterklasse ist, die Ganzzahlen repräsentiert. das Beispiel könnte dann so aussehen:
Code: Alles auswählen
public static void main(String[] args) {
Function f = new Function() {
public Obj apply(Obj n) {
return n.multiply(n);
}
};
for (Tuple t : Python.enumerate(Python.map(f, Python.range(10)))) {
Obj i = t.get(0);
Obj r = t.get(1);
Python.print(i, r);
}
}
Bei diesem Ansatz punktet sogar die JVM mit ihrem JIT gegen einen statischen Compiler, da sie durch dynamisches Inlinning und Typanalyse sowie das Umschreiben der Programme die eigentlich statischen Pfade im Programm finden und optimalen Maschinencode dafür erzeugen kann - das gelingt einem C-Compiler durch statische Analyse des Quelltextes nicht.
Stefan