IronPython und Mono

Probleme bei der Installation?
Leonidas
Python-Forum Veteran
Beiträge: 16025
Registriert: Freitag 20. Juni 2003, 16:30
Kontaktdaten:

sma hat geschrieben:Das sich IronPython die Performance mit höherem Speicheraufwand erkauft, sollte klar sein. Ebenso wird die Startzeit bedingt durch die VM-Technologie größer sein - beides ist aber für viele Anwendungen egal, da es dort um länger laufende Prozesse gibt, wo man Speicher und Startzeit gerne gegen zusätzliche Performance tauscht.
Wenn es nach Microsoft ging, gäbe es mehr .NET-Applikationen und somit wären zumindest die Kernbibliotheken von .NET sowieso im Speicher, da wäre der Aufwand neue Programme zu starten gar nicht mal so groß.
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

Nachtrag: Im April 2007 hat der Autor CPython 2.5 mit IronPython 1.1 unter Windows vergleichen: ipy = 1,7x cpy.

Zu diesem Zeitpunkt war Mono langsamer als Windows .NET.

Update 1: Hier hat google noch einen Benchmark von Jython 2.3 vs. CPython 2.4 ausgegraben. Jython erreicht 72% der Performance, ist also langsamer. (Ich finde ja nett, dass der Testrechner Cthulhu heißt... Netter Namensraum für Rechner. Wie wäre es mit Shub-Niggurath oder Ghatanothoa...

Update 2: Habe jetzt sebst Pybench für CPython 2.5 und Jython 2.5a1 ausgeführt. Mein Mac hat keinen so schicken Namen, braucht dafür nur ca. 6.3sek für den Benchmark. Jython schlägt sich mit der Java 1.6 64-bit-Server-VM recht gut. Nach einigen Aufwärmrunden liegt die Zeit ebenfalls bei 6.3sek. Dafür braucht Jython aber ~70 MB Hauptspeicher, nicht ~5MB wie CPython. Auch schafft es Jython, 150% CPU-Leistung zu ziehen, während CPy bei 99% bleibt. Java 1.5 Server (32-bit) bringst nicht und bleibt bei etwa 7sek stehen. Dafür braucht es "nur" ~50MB. Java 1.5 Client (32-bit) ist mit 11sek Schlusslicht.

Stefan
Leonidas
Python-Forum Veteran
Beiträge: 16025
Registriert: Freitag 20. Juni 2003, 16:30
Kontaktdaten:

Super dass mal jemand das wieder getestet hat, schade nur dass ohne IronPython. Aber das könnte man unter Mac wohl nur auf Mono testen. Ales in allem scheint aber IronPython für Linux-Setups generell eher wenig interessant zu sein, denn Mono wird immer noch eine schlechte Performance nachgesagt. :-/ Konkrete Messungen habe ich aber dazu nicht gesehen.

Apropos Java-Benchmarks wäre es generell mal interessant wie sich die verschiedenen Sprachen auf der JVM (etwa JRuby, Jython, Scala, Clojure) bei den gleichen Aufgaben schlagen.
My god, it's full of CARs! | Leonidasvoice vs (former) Modvoice
burli
User
Beiträge: 1156
Registriert: Dienstag 9. März 2004, 18:22

Wo finde ich denn die Sourcen für den Benchmark. Vielleicht kann ich hier mal CPython und IronPython (Mono) miteinander vergleichen. Wenn Ich Windows dazu überreden kann IronPython zu verwenden kann ich es da auch mal testen
Leonidas
Python-Forum Veteran
Beiträge: 16025
Registriert: Freitag 20. Juni 2003, 16:30
Kontaktdaten:

burli hat geschrieben:Wo finde ich denn die Sourcen für den Benchmark.
Im Python SVN-Tree.
My god, it's full of CARs! | Leonidasvoice vs (former) Modvoice
burli
User
Beiträge: 1156
Registriert: Dienstag 9. März 2004, 18:22

Hm, bei mir spuckt IronPython einen Fehler aus

Code: Alles auswählen

~/pybench$ ipy pybench.py
-------------------------------------------------------------------------------
PYBENCH 2.0
-------------------------------------------------------------------------------
* using Python 2.4.0 (IronPython 1.1.1 (1.1.1) on .NET 2.0.50727.42)
* Python version doesn't support gc.disable
* Python version doesn't support sys.setcheckinterval
* using timer: time.time


* Internal Error (use --debug to display the traceback)
Leonidas
Python-Forum Veteran
Beiträge: 16025
Registriert: Freitag 20. Juni 2003, 16:30
Kontaktdaten:

(use --debug to display the traceback)
My god, it's full of CARs! | Leonidasvoice vs (former) Modvoice
burli
User
Beiträge: 1156
Registriert: Dienstag 9. März 2004, 18:22

Hab ich schon probiert. Da kommt nur etwas sehr merkwürdiges bei raus. Irgendwas stimmt da nicht

Bild

Er scheint etwas auszugeben, aber man kann nix lesen
burli
User
Beiträge: 1156
Registriert: Dienstag 9. März 2004, 18:22

Korrektur: er hat was ausgegeben, aber in der gleichen Farbe wie der Hintergrund. War nicht zu erkennen

Code: Alles auswählen

~/pybench$ ipy pybench.py --debug
-------------------------------------------------------------------------------
PYBENCH 2.0
-------------------------------------------------------------------------------
* using Python 2.4.0 (IronPython 1.1.1 (1.1.1) on .NET 2.0.50727.42)
* Python version doesn't support gc.disable
* Python version doesn't support sys.setcheckinterval
* using timer: time.time

Traceback (most recent call last):
  File CommandLine, line unknown, in __init__
  File pybench, line unknown, in main
  File pybench, line unknown, in __init__
  File pybench, line unknown, in __init__
  File pybench, line unknown, in get_machine_details
  File platform, line unknown, in python_build
  File platform, line unknown, in _sys_version
AttributeError: 'NoneType' object has no attribute 'groups'
sma
User
Beiträge: 3018
Registriert: Montag 19. November 2007, 19:57
Wohnort: Kiel

Leonidas hat geschrieben:Apropos Java-Benchmarks wäre es generell mal interessant wie sich die verschiedenen Sprachen auf der JVM (etwa JRuby, Jython, Scala, Clojure) bei den gleichen Aufgaben schlagen.
Ich denke, das ist recht schwer, hier aussagekräftige Benchmarks zu finden. Der Programming Language Shootout kann ein Indiz sein, aber das fehlen Jython und Clojure.

Ich würde tippen, dass Java selbst die Liste anführen würde. Danach kommt dann Scala, was bei gleicher semantischen Komplexität auch in etwa den gleichen Bytecode erzeugen wird und damit von der Laufzeit vergleichbar ist. Hier wäre höchstens interessant, wie viel z.B. eine rein funktionale Lösung an Laufzeit kostet. Ich tippen weiter, dass dann Clojure folgt, welches sich ebenfalls recht stark an den Möglichkeiten bzw. Unmöglichkeiten der JVM orientiert und etwa den Anwender zwingt, auf Rekursion zu verzichten und statt dessen `recur` und `loop` Specialforms einzusetzen. JRuby ist dann schneller als Jython, in erster Linie, weil dort wesentlich mehr Arbeit in die Optimierung geflossen ist. Beide Sprachen wehren sich eigentlich mit Händen und Füßen, in ein so starres Konzept wie die JVM gepresst zu werden und man muss viel Überredungskunst in Form von komplizierten Optimierungen einsetzen, um da etwas zu reißen.

Eine sehr schnelle und dennoch einfache JVM-basierte Scriptsprache ist übrigens Pnuts und Rhino (JavaScript) sollte man auch nicht vergessen. Dann wäre auch ein Blick auf ein echtes Scheme (SISC) oder CommonLisp (ABCL) interessant. Und natürlich darf man Groovy nicht vergessen.

Übrigens, den Ansatz von Cython, also ein Subset von C mit Syntax von Python, welches sich leicht und effizient in C übersetzen lässt aber dennoch für Python-Entwickler eine vertraute Syntax bietet, müsste man doch auch für Java einsetzen können. Ähnlich fing ja Groovy an - man wollte etwas wie Java, das sich aber mit weniger Schmerzen schreiben lässt. Und auch RPython fällt doch in diese Kategorie - ein um dynamische Features beraubtes Subset von Python, welches sich effizient in eine statische Programmiersprache übersetzen lässt.

Stefan
burli
User
Beiträge: 1156
Registriert: Dienstag 9. März 2004, 18:22

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
Leonidas
Python-Forum Veteran
Beiträge: 16025
Registriert: Freitag 20. Juni 2003, 16:30
Kontaktdaten:

sma hat geschrieben:Und auch RPython fällt doch in diese Kategorie - ein um dynamische Features beraubtes Subset von Python, welches sich effizient in eine statische Programmiersprache übersetzen lässt.
Also meinst du RPython auf der JVM?

Was die Performancereihenfolge angeht hätte ich da ganz ähnlich geschätzt, lediglich Scala habe ich mir nicht ausreichend angesehen und da schätzen zu können. Was aber die Limitierungen der JVM angeht hat Rich Hickey (die treibende Kraft hinter Clojure) meiner Meinung nach noch Tail-Call-Optimization in Zukunft nachzuholen denn ``recur`` scheint drangekleistert zu sein, nicht so wie in Scheme. Zudem das Problem eigentlich lösbar ist, denn soweit ich weiß unterstützt Bigloo auf der JVM TCO ohne Probleme. Man muss es eben selbst Optimieren, da die JVM sowas nicht selbst kann, aber es ist nicht ausgeschlossen dass spätere Clojure-Versionen das nachrüsten wenn mehr Interesse da ist.
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
Da vermischst du etwas.

IronPython-Programme werden (zumindest als ich zuletzt reingeschaut habe) ja auch in IL kompiliert, nur ist dieser Code nicht so einfach wie der entsprechende C# Code und braucht länger in der Ausführung, weil eben bei Python zur Laufzeit mehr passiert.

Der IronPython-Interpreter ist aber weder in Python noch in IL geschrieben. Analog dazu ist der CPython Interpreter in C geschrieben und produziert ebenso Bytecode, nur eben Python-Bytecode.
My god, it's full of CARs! | Leonidasvoice vs (former) Modvoice
burli
User
Beiträge: 1156
Registriert: Dienstag 9. März 2004, 18:22

Leonidas hat geschrieben:Der IronPython-Interpreter ist aber weder in Python noch in IL geschrieben. Analog dazu ist der CPython Interpreter in C geschrieben und produziert ebenso Bytecode, nur eben Python-Bytecode.
Aber Python Bytecode wird doch direkt interpretiert. .NET wird zur Laufzeit in nativen Code compiliert, oder?
Leonidas
Python-Forum Veteran
Beiträge: 16025
Registriert: Freitag 20. Juni 2003, 16:30
Kontaktdaten:

burli hat geschrieben:Aber Python Bytecode wird doch direkt interpretiert. .NET wird zur Laufzeit in nativen Code compiliert, oder?
Ja, durch den JIT-Compiler. Aber das ist keine .NET-Spezialität, das haben die JVM, PLT Scheme, PyPy und viele andere auch.

Fakt ist: auch wenn man den Code zu nativen Code kompiliert, ist es langsamer als C#, schlicht weil eben mehr Code ausgeführt werden muss.
My god, it's full of CARs! | Leonidasvoice vs (former) Modvoice
burli
User
Beiträge: 1156
Registriert: Dienstag 9. März 2004, 18:22

Leonidas hat geschrieben:Ja, durch den JIT-Compiler. Aber das ist keine .NET-Spezialität, das haben die JVM, PLT Scheme, PyPy und viele andere auch.
PyPy ist ein JIT? Das verwirrt mich jetzt weil bei mir pypy ein Python in Python Interpreter ist
Leonidas
Python-Forum Veteran
Beiträge: 16025
Registriert: Freitag 20. Juni 2003, 16:30
Kontaktdaten:

burli hat geschrieben:
Leonidas hat geschrieben:Ja, durch den JIT-Compiler. Aber das ist keine .NET-Spezialität, das haben die JVM, PLT Scheme, PyPy und viele andere auch.
PyPy ist ein JIT? Das verwirrt mich jetzt weil bei mir pypy ein Python in Python Interpreter ist
PyPy hat einen JIT (AFAIR sogar mehr noch, einen JIT-Generator). PyPy ist weniger ein Interpreter (das auch), sondern mehr eine Compiler-Infrastruktur.

sma, wie ich inzwischen rausgefunden habe, gibt es RPython auf der JVM.
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

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
sma
User
Beiträge: 3018
Registriert: Montag 19. November 2007, 19:57
Wohnort: Kiel

Ich habe eben gerade noch ein bisschen gespielt. Ich glaube, das wird jetzt ziemlich OT.

Dieses Java-Programm (notwendiges Laufzeitsystem auf Anfrage) braucht auf meinem Rechner etwa 7ms für fib(28). CPython 2.5 braucht dafür 340ms.

Code: Alles auswählen

  static Obj fib(Obj n) {
    if (n.lessThan(_2)) {
      return _1;
    } else {
      return fib(n.subtract(_1)).add(fib(n.subtract(_2)));
    }
  }
Das Java-Programm ist offensichtlich nicht so flexibel wie Python, denn ich kann z.B. nicht einfach die globale Variable "fib" überschreiben - es gibt sie nicht. Ich kann auch nicht mittels "locals()" auf das "n" zugreifen. Der Kontext in Form von Frame-Objekten existiert ebenfalls nicht.

Sind derartige Funktionen verzichtbar, kann man in einem Subset von Python programmieren, welches sich recht effizient nach Java übersetzen lässt.

Definiere ich fib als Exemplar eine Klasse "Function", beträgt die Laufzeit etwa 8ms. Das ist noch erträglich. Jetzt kann ich "fib" ändern, habe nach wie vor gehen weder locals() noch globals().

Code: Alles auswählen

  static Function fib = new Function() {
    @Override
    Obj call(Obj n) {
      if (n.lessThan(_2)) {
        return _1;
      } else {
        return fib.call(n.subtract(_1)).add(fib.call(n.subtract(_2)));
      }
    }
  };
Benutze ich ein Dict, um globale Werte zu speichern, bricht mir die Performance auf 33ms (50ms wenn ich die Strings nicht cache und 19ms wenn ich Strings interniere - also einzigartig mache) ein. Ich nutze eine java.util.HashMap als Implementierung.

Code: Alles auswählen

  static Dict globals = Dict();
  static {
    globals.setItem(s_fib, new Function() {
      @Override
      Obj call(Obj n) {
        if (n.lessThan(_2)) {
          return _1;
        } else {
          return globals.getItem(s_fib).call(n.subtract(_1)).add(globals.getItem(s_fib).call(n.subtract(_2)));
        }
      }
    });
  }
Baue ich mir ein für diesen Benchmark optimales Dict, welches sich eine Anfrage merkt und bei selben Key den gemerkten Wert liefert und nicht in die java.util.HashMap schaut, komme ich auf 11ms runter.

Benutze ich auch für das lokale "n" ein dict, bin ich bei 340ms. Ahme ich also möglichst genau die Python-Semantik nach, muss ich auch mit Pythons Ausführungszeit leben.

Mit einer speziellen Dict-Implementierung für lokale Variablen kann ich die Zeit nochmal auf 109ms drücken, ich denke aber, das ist nur deswegen so extrem, weil ich in fib nur eine Variable habe. Simuliere ich 4 Variablen, bin ich bei 250ms (200ms bei 3 Variablen).

Führe ich ein Frame-Objekt ein, kann ich dort lokale Variablen verwalten. Das erlaubt, locals(), doch Frame-Objekte müssen jetzt parallel zu Javas normalem direkt in der VM verwalteten Stack von Activations verwaltet werden und ich komme auf 98ms (ThreadLocal-Variable) bzw. 64ms (einfache globale Variable). Eine Alternative, die ich in Smython benutze ist, den Frame überall durchzureichen. Das ist mit 62ms in diesem Beispiel geringfühig schneller. Locals lässt sich dann so implementieren:

Code: Alles auswählen

new BuiltinFunction() {
  @Override
  Obj call(Frame frame) {
    return frame.back.locals();
  }
}
Alle Zeiten mit JDK 1.6 64-bit im Sever-Modus gemessen.
Stefan
Antworten