Nach CPython und Jython jetzt V8python?

Alles, was nicht direkt mit Python-Problemen zu tun hat. Dies ist auch der perfekte Platz für Jobangebote.
Antworten
sma
User
Beiträge: 3018
Registriert: Montag 19. November 2007, 19:57
Wohnort: Kiel

V8 ist die neue Open Source JavaScript-Engine von Google, entwickelt von Leuten die zuvor an der Self-VM, Strongtalk und der Hotspot-Java-VM gearbeitet hatten. Die sollten eigentlich wissen, was sie tun, auch wenn V8 (bislang) nicht an die Qualität der Optimierungen von Self und Strongtalk erreicht. In der Squeak-dev-ML befand man V8 auf VisualWorks-Smalltalk-Niveau, welches das schnellste kommerzielle Smalltalk ist, aber nicht an das Forschungsprojekt Strongtalk (übrigens auch als Open Source verfügbar) rankommt. Dafür läuft Strongtalk auch nicht 100% stabil und hat keinen Debugger. Nichts desto trotz kann sich wohl nur der auf ganz andere Art arbeitende TraceMonkey von Mozilla auf Augenhöhe mit V8 messen. Die Interpreter SpiderMonkey und SquirrelFish sowie Rhino oder auch was Microsoft so hat, haben keine Chance gegen diese neue Generation von hochoptimierenden JavaScript-Engines.

Das führt zu der Frage: Kann man die Engine nur für JavaScript oder auch für andere Sprachen wie Python nutzen? Python, kompiliert auf die JVM, ist nur etwa gleich schnell wie CPython, was ein reiner Bytecode-Interpreter ist. Da muss doch mehr möglich sein.

Da Python deutlich ähnlicher zu JavaScript wie Java ist, könnte es doch von V8 profitieren...

Ich habe bislang nur kurz in den Quelltext (alles C++, würg) geschaut und fib(32) ausprobiert. Dabei habe ich offenbar den Sweetspot von V8, nämlich Rekursion, getroffen. Das Ding ist bei diesem Benschmark schnell... verdammt schnell.

Ein kleines Subset von Python lässt sich relativ einfach effizient in JavaScript übersetzen. Das liefe dann wahrscheinlich deutlich schneller. Anderes müsste man ausprobieren.

Die prototypische Delegation von JS sollte eigentlich ermöglichen, die Vererbung von Python nachzustellen. Ich nehme an, dass die Methodensuche bei V8 stark optimiert wird (habe von monomorphic inline caches gelesen) sodass das effizient genug funktioniert. Mehrfachvererbung mit ihrer speziellen MRO kommt ja eigentlich relativ selten vor. Das einfachere Vererbungsmodell von Smalltalk und Ruby wären hier leichter abzubilden.

Pythons Grunddatentyp ist das `dict`. Das entspricht im Prinzip einem Objekt bei JS, doch dieses hat einige immer gegenwärtige Attribute. Dieses also mit einer eigenen Klasse zu simulieren wirkt unschön. Natürlich könnte es ein externer Typ sein, den man dann in C++ schreibt.

JS kennt nur einen numerischen Datentyp, Python hingegen 3 bis 4, je nachdem ob man `int` und `long` unterscheidet. Dabei halte ich `complex` für entbehrlich. Auch hier könnte man den Teil in C++ schreiben. Wahrscheinlich verbaut man sich dabei aber jetzt vorhandene Optimierungen.

Python kennt des weiteren diverse "__"-Methoden, mit denen man Standardverhalten überschreiben kann. Dies scheint mir das größte Problem bei einer möglichen Portierung zu sein. Speziell für `__getattr__` und Freunde wäre es hilfreich, eine Art `doesNotUnderstand` oder `method_missing` Funktion bereits nativ zu haben.

Pythons Funktionsargumente sind komplexer aufgebaut als die von JS, indem immer noch ein `dict` mit Schlüsselwortargumenten vorhanden sein kann und diese auf recht komplexe Weise zusammen mit Standardargumenten verknüpft werden. Hier bekommt man wahrscheinlich pro Funktionsaufruf einen mächtigen Performance-Overhead, wenn die VM das nicht speziell behandeln kann.

Aber gibt es weitere prinzipielle Probleme?

Ist das überhaupt eine interessante Idee?

Stefan
audax
User
Beiträge: 830
Registriert: Mittwoch 19. Dezember 2007, 10:38

PyPy hat als Ziel, Python zu JavaScript zu kompilieren und das klappt auch schon.
Leonidas
Python-Forum Veteran
Beiträge: 16025
Registriert: Freitag 20. Juni 2003, 16:30
Kontaktdaten:

sma hat geschrieben:Nichts desto trotz kann sich wohl nur der auf ganz andere Art arbeitende TraceMonkey von Mozilla auf Augenhöhe mit V8 messen. Die Interpreter SpiderMonkey und SquirrelFish sowie Rhino oder auch was Microsoft so hat, haben keine Chance gegen diese neue Generation von hochoptimierenden JavaScript-Engines.
Warum siehst du V8 SquirrelFish davonrennen? Also in den Benchmarks die ich gesehen habe, hat SquirrelFish durchaus gut abgeschnitten. Es gibt nur eben bisher noch kein Browser-Release, das den nutzen würde.
My god, it's full of CARs! | Leonidasvoice vs (former) Modvoice
sma
User
Beiträge: 3018
Registriert: Montag 19. November 2007, 19:57
Wohnort: Kiel

Leonidas hat geschrieben:Warum siehst du V8 SquirrelFish davonrennen?
Nach meinem Wissen ist SquirrelFish ein Interpreter. V8 kompiliert in x86 oder ARM-Maschinencode. Das ist in aller Regel schneller. V8 leistet sich daher den Luxus, fast alle Bibliotheksfunktionen ebenfalls in JavaScript zu implementieren und das scheint mir zur Zeit der Grund, warum die anderen Interpreter je nach Benchmark nicht so schlecht aussehen. Das kann sich aber ändern, wenn sie dort zu optimieren beginnen.
audax hat geschrieben:PyPy hat als Ziel, Python zu JavaScript zu kompilieren und das klappt auch schon.
Vollständig? Inklusive der ganzen "__"-Methoden und Zugriff auf Frames?

Das es prinzipiell geht, ist klar. Doch darum ging es mir weniger. Meine Überlegung ist, dass mit V8 eine JavaScript-Engine zur Verfügung steht, die "hackable" ist und die man möglicherweise derart an die Bedürfnisse von Python anpassen kann, dass man nicht nur effektiv sondern auch effizient übersetzen und ausführen kann.

Ich habe mal `fib(25)` mit Firefox (Spidermonkey) und v8 sowie mit Python 2.5.1 verglichen. Firefox braucht 152ms, Python 82ms und V8 schafft es in 4ms. Diese Funktion testet im wesentlichen Funktionsaufrufe und ein bisschen Arithmetik.

Simuliere ich in JavaScript die Semantik von Python, sieht das ungefähr so aus:

Code: Alles auswählen

    globals.__setitem__("fib", new PyFunction("fib", globals, function(frame) {
        var n = frame.locals[0];
        if (n.__lt__(2).__nonzero__()) {
            return 1;
        }
        return frame.globals.__getitem__("fib").__call__(frame, [n.__sub__(1)]).__add__(
            frame.globals.__getitem__("fib").__call__(frame, [n.__sub__(2)]));
    }));
Dafür braucht Firefox mehr als 5000ms, V8 schafft es in 65ms! Für `fib(30)` (Firefox schafft das nicht mehr) braucht V8 nativ 35ms, Python 820ms und meine Simulation 640ms.

Das ist schneller als Python selbst. Ich hätte mir eigentlich einen noch deutlicheren Vorsprung erhofft und frage mich, welches die teuersten Operationen sind. Das Zurückbauen von __lt__ oder __add__ und __sub__ bringt aber erstaunlich wenig. Auch das zweimaligen Suchen nach fib ist nicht so teuer wie ich gedacht hätte. Ich glaube, die Frame-Objekte sind der größte Zeitfresser. Wenn ich diesen weglasse und direkt `locals` und `globals` übergebe, brauche ich noch 465ms.

In diesem nicht (repräsentativen) Beispiel erreiche ich durch V8 nahezu eine Verdopplung der Ausführungsgeschwindigkeit, was Methodenaufrufe angeht. Dabei habe ich V8 nicht verändert.

In Smalltalk würde man `fib` in der Klasse `Integer` implementieren:

Code: Alles auswählen

    fib
        ^self < 2 ifTrue: [1] ifFalse: [(self - 1) fib + (self - 2) fib]
Auch dies kann ich in JavaScript simulieren:

Code: Alles auswählen

    Number.prototype["fib"] = function() {
        if (this["<"](2)) {
            return 1;
        }
        return this["-"](1)["fib"]()["+"](this["-"](2)["fib"]());
    };
Squeak (ein Smalltalk-Interpreter) braucht 200ms für `fib(30)`. V8 braucht 95ms (nativ waren es 35ms). Methodenaufruf und Methodensuche sind bei Smalltalk und JavaScript kompatibel, daher habe ich es als Beispiel gewählt. Dies zeigt, was möglich wäre, wenn man V8 dahin bekäme, kompatibel zu Pythons Aufrufsemantik zu sein.

Stefan
sma
User
Beiträge: 3018
Registriert: Montag 19. November 2007, 19:57
Wohnort: Kiel

Gestern Nacht habe ich einen Übersetzer von Python nach JavaScript gehackt, der als Proof of Principle die Datei "pystone.py" übersetzen kann.

Leider ist die Performance nicht so gut, wie ich gehofft hatte: CPython 59363.4, Spidermonkey (FF3) 4094.3, V8 15893.2 (je höher, desto besser). Ich erreiche also etwa 1/4 der Geschwindigkeit von CPython. Dafür ist V8 fast 4x schneller als SM. Gerne würde ich auch SquirelFish Extreme ausprobieren, weiß aber nicht, wie ich den Interpreter alleine bauen soll.

Doch wie soll ich sonst mit optionalen Parametern klarkommen? Von Schlüsselwortparametern will ich ja noch gar nicht reden (da ich diese nicht implementiert habe).

Bei Interesse mehr Infos ;)

Stefan
epsilon
User
Beiträge: 71
Registriert: Freitag 20. Juni 2008, 19:48

Hallo sma,

hast du diese Seite schon gesehen? Wenn nicht, interessiert dich das vielleicht.
sma
User
Beiträge: 3018
Registriert: Montag 19. November 2007, 19:57
Wohnort: Kiel

Ja, gesehen schon - aber noch nicht ausprobiert. Insbesondere wundert micht, dass sie behaupten, für fib() schneller als Python zu sein, was mir nicht gelungen ist. Ansonsten war meine Idee nicht unbedingt, einen "Nachbrenner" für den normalen Python-Interpreter zu haben, sondern einen Ersatz für ein ausreichend großes Subset von Python, dass dann auch in einem Browser (inkl. IDE) laufen könnte. Ein bisschen so wie der Lively Kernel. Nichtsdesttrotz aber spannend. Leider haben die V8-Entwickler mehrfach gesagt, dass sie nicht an einer allgemeinen VM jenseits der Anforderungen für JavaScript interessiert sind, sodass V8 sich wahrscheinlich weg von einer universell brauchbaren VM hin zu einem System speziell für die Anforderungen von JavaScript entwickeln wird. Für Python bräuchte man (genau wie für Smalltalk oder Ruby) so "catch-all"-Funktionen für unbekannte Attribute. Interessanterweise hat Spidermonkey dies mit einer "__noSuchMethod__"-Methode, die auch in ECMAScript 3.1 aufgenommen werden soll... noch ist da also Hoffnung.

Stefan
Antworten