2009-11-26 9 views
18

Aus welchen technischen Gründen werden Sprachen wie Python und Ruby interpretiert (out of the box) statt kompiliert? Es scheint mir, als ob es für Leute, die in diesem Bereich gut informiert sind, nicht zu schwierig sein sollte, diese Sprachen nicht so zu interpretieren, wie sie es heute sind, und wir würden signifikante Leistungssteigerungen sehen. Also ich vermisse bestimmt etwas.Warum wird (Python | Ruby) interpretiert?

+2

Die Tatsache, dass (zumindest Python) seit Jahren mehr als ein Compiler-Projekt hatte, und dass es immer noch nicht ganz da ist, sollte Ihre Erwartungen von "nicht zu schwer" nüchtern sein, denke ich. –

+5

Eigentlich denke ich, Python kompiliert zu virtuellem Maschinencode, ähnlich wie .NET und Java. So oder so, ich denke, dass Sprachumsetzer die Wahl der Interpretation oder Kompilation eine gute Frage sind. Sie können http://stackoverflow.com/questions/475223/what-is-the-difference-between-implementing-a-compiler-and-an-interpreter überprüfen –

+2

Sie könnten auch interessiert sein an folgende Antwort: http : //stackoverflow.com/questions/376611/why-interpreted-langes-are-mostly-ducktyped-while-compiled-have-strong-typing/376828#376828 –

Antwort

1

Durch Entwurf.

Die Autoren wollten etwas, wo sie Skripte schreiben können.

Python wird das erste Mal kompiliert es aber

+0

dh "Byte kompiliert" (zu. Pyc) das erste Mal es wird ausgeführt. Dies beschleunigt nur die Ladezeiten zukünftiger Ausführungen. Ich denke, der Fragesteller spricht davon, dass er in den nativen Maschinencode übersetzt wird. – overthink

+0

Perl auch ... seufzt, fragt kein Körper nach Perl. – dlamblin

+1

"Die Autoren wollten etwas, wo sie Skripte schreiben können."? Diese Aussage verwirrt mich. Die Eignung des Zwecks für gegebene Aufgaben einer gegebenen Sprache hat viel weniger mit seinem 'Schreiben/(Kompilieren, Verknüpfen)/Lauf-Zyklus zu tun als der Reichtum einer Standardbibliothek, eines Speichermanagements und eines Typmodells. Das würde wahrscheinlich auch Unterstützung für das Schreiben von Skripten in Java bieten, wenn es keine andere kleine Überlegung darüber gäbe, wie viel Aufwand es braucht, um die virtuelle Maschine zu starten ... –

2

gut ausgeführt wird, ist nicht eine der Stärken dieser Sprachen, die sie so leicht skriptfähig sind? Sie wären nicht, wenn sie kompiliert würden. Auf der anderen Seite sind dynamische Sprachen einfacher zu interpretieren als zu kompilieren.

6

Ich denke, der wichtigste Grund für die Sprachen interpretiert wird Portabilität. Als Programmierer können Sie Code schreiben, der in einem Interpreter ausgeführt wird, nicht in einem bestimmten Betriebssystem. Ihre Programme verhalten sich also mehr plattformübergreifend (mehr als kompilierte Sprachen). Ein weiterer Vorteil, den ich mir vorstellen kann, ist, dass es einfacher ist, ein dynamisches System in einer interpretierten Sprache zu haben. Ich denke, dass die Schöpfer der Sprache eine Sprache haben, in der Programmierer aufgrund der automatischen Speicherverwaltung produktiver sein können, dynamisches Typsystem und Metaprogrammierung über jeden Leistungsverlust aufgrund der Sprache, die interpretiert wird, gewinnt. Wenn Sie sich Sorgen um die Leistung machen, können Sie die Sprache immer mit dem nativen Maschinencode kompilieren, indem Sie eine Technik wie die JIT-Kompilierung verwenden.

+0

Ich bin mir nicht sicher, ob das Portabilitätsargument vernünftig ist. Wenn Sie Ihren Lexer/AST-Builder von Ihrem Code-Generierungs-Backend entkoppeln, können Sie die beiden unabhängig voneinander variieren (was in etwa so aussieht, wie gcc aufgebaut ist). Also sehe ich nicht, dass das der Grund ist. Ihr Standpunkt zu einem dynamischen System, das in einer interpretierten Sprache einfacher zu implementieren ist, ist Klang. Tatsächlich benötigt jedes dynamische System eine Laufzeitunterstützung (entweder durch einen Interpreter oder durch eine Laufzeitbibliothek) praktisch per Definition. –

+0

Das Tragbarkeitsargument ist in Wirklichkeit überhaupt nicht stichhaltig. Interpretierte Sprachen sind in der Regel nicht einfacher zu portieren als kompilierte. Der einzige Grund, warum sie * scheinbar * einfacher zu portieren scheinen, ist, dass Sie Ihren interpretierten Sprachport schreiben können, ohne die zugrundeliegende Maschine zu verstehen, aber das ist nur eine Frage der Kompetenz, nicht der Schwierigkeit. –

+0

ihr habt Recht..das ist alles falsch ausgegangen! Ich werde meine Antwort aktualisieren, um zu sagen, was ich wirklich denke. – neesh

2

In einer kompilierten Sprache, die Schleife Sie in zu erhalten, wenn die Software zu machen ist

  1. Nehmen Sie eine Änderung
  2. Compile ändert
  3. -Test ändert
  4. goto 1

interpretierte Sprachen tendieren dazu, schneller zu sein, um Sachen zu machen, weil du Schritt zwei dieses Prozesses ausschneiden musst (und wenn du es mit einem großen System zu tun hast) Wenn die Kompilierzeit mehr als zwei Minuten betragen kann, kann Schritt zwei eine beträchtliche Zeit hinzufügen.

Dies ist nicht unbedingt der Grund, warum Python | Ruby Designer gedacht haben, aber bedenken Sie, dass "Wie effizient die Maschine das ausführt?" ist nur die Hälfte des Problems der Softwareentwicklung.

Es scheint auch so, als wäre es einfacher, Code in einer Sprache zu kompilieren, die natürlich interpretiert wird, als wenn man einer Sprache, die standardmäßig kompiliert wird, einen Interpreter hinzufügen würde.

32

Mehr Gründe:

  • schnellere Entwicklung Schleife, Schreibtest vs write-kompilieren-Link-Test
  • einfacher für dynamisches Verhalten zu ordnen (Reflexion, metaprogramming)
  • Marken das ganze System tragbar (nur den zugrunde liegenden C-Code neu kompilieren und Sie sind gut auf eine neue Plattform gehen)

Denken Sie daran, was passieren würde, wenn das System nicht interpretiert würde. Angenommen, Sie haben die Übersetzung nach C als Mechanismus verwendet. Der kompilierte Code müßte in regelmäßigen Abständen überprüfen, ob es durch metaprogramming abgelöst worden war. Eine ähnliche Situation tritt bei eval()-Typ-Funktionen auf. In diesen Fällen müsste es den Compiler erneut ausführen, ein unverschämt langsamer Prozess, oder es müsste auch den Interpreter sowieso zur Laufzeit haben.

Die einzige Alternative hier ist ein JIT-Compiler. Diese Systeme sind sehr komplex und hochentwickelt und haben noch größere Laufzeiten als alle anderen Alternativen. Sie starten sehr langsam und machen sie für Scripting unpraktisch. Hast du jemals ein Java-Skript gesehen? Ich habe nicht.

Also, haben Sie zwei Möglichkeiten:

  • alle Nachteile sowohl von einem Compiler und einen Dolmetscher
  • nur die Nachteile eines Dolmetschers

Es ist nicht verwunderlich, dass in der Regel die primäre Umsetzung geht nur mit der zweiten Wahl. Es ist durchaus möglich, dass wir eines Tages sekundäre Implementierungen wie Compiler sehen werden. Ruby 1.9 und Python haben Bytecode-VMs; das sind & frac12; -Wege dorthin. Ein Compiler zielt möglicherweise nur auf nicht-dynamischen Code ab, oder es können verschiedene Ebenen der Sprachunterstützung als Optionen deklarierbar sein. Da aber so etwas kann nicht die primäre Umsetzung sein, stellt es eine Menge Arbeit für einen sehr marginalen Nutzen. Ruby hat bereits 200.000 Zeilen C drin ...

Ich sollte hinzufügen, dass man immer eine kompilierte C (oder, mit etwas Aufwand, jede andere Sprache) Erweiterung hinzufügen kann. Also, sagen Sie, Sie haben eine langsame numerische Operation. Wenn Sie hinzufügen, sagen Array#newOp mit einer C-Implementierung erhalten Sie den Speedup, bleibt das Programm in Ruby (oder was auch immer) und Ihre Umgebung bekommt eine neue Instanz Methode. Jeder gewinnt! So verringert sich die Notwendigkeit für eine problematische Sekundär Umsetzung.

+5

"Haben Sie jemals ein Java-Skript gesehen? Ich habe es nicht getan." Ha! Ihre Reputationspunkte könnten 30x mehr sein als meine, aber selbst ich habe von JavaScript gehört! – mtyaka

+4

Hehe, das ist gut. Eigentlich lerne ich viel über SO, und ich weiß, dass ich noch viel zu lernen habe. Aber, trotz des englischen Wortspiels, (1) mit "Skript" meinte ich "ein Shell-ausgeführtes Skript, wie in bash oder perl"; (2) Ich habe noch nie einen von denen in JS gesehen, und (3) JS hat so gut wie überhaupt nichts mit Java zu tun. – DigitalRoss

+3

@ mtyaka: Er meint eindeutig "in Java geschriebenes Skript", nicht "Javascript", was eine völlig andere Sprache ist. @DigitalRoss: Tatsächlich gewinnt Javascript mit der Einführung eigenständiger Interpreter wie V8 und SquirrelFish als Nicht-Web-Skriptsprache an Popularität. –

5

Heute gibt es keine starke Unterscheidung zwischen "kompilierten" und "interpretierten" Sprachen. Python ist nur als kompilierte in der Tat viel wie Java ist, sind die einzigen Unterschiede:

  • Der Python-Compiler ist viel schneller als der Java-Compiler
  • Python kompiliert automatisch Quellcode wie er ausgeführt wird, gibt es keine getrennte „Übersetzen“ Schritt erforderlich
  • Python Bytecode unterscheidet sich von JVM Bytecode

Python hat auch eine Funktion namens compile() die eine Schnittstelle zu dem Compiler ist.

Es klingt wie die Unterscheidung, die Sie treffen, zwischen "dynamisch typisierten" und "statisch typisierten" Sprachen.

def fn(x, y): 
    return x.foo(y) 

Beachten Sie, dass die Arten von x und y nicht angegeben werden: In dynamischen Sprachen wie Python, können Sie Code wie schreiben. Zur Laufzeit wird diese Funktion x betrachten, um zu sehen, ob es eine Elementfunktion namens foo hat, und wenn ja, wird sie mit y aufgerufen. Wenn nicht, wird ein Laufzeitfehler ausgegeben, der anzeigt, dass keine solche Funktion gefunden wurde. Diese Art der Laufzeitsuche ist viel einfacher darzustellen, indem eine Zwischenrepräsentation wie der Bytecode verwendet wird, wobei eine Laufzeit - VM die Suche durchführt, anstatt Maschinencode zu generieren, um die Suche selbst durchzuführen (oder eine Funktion zum Suchen aufzurufen Bytecode wird es trotzdem tun).

Python hat Projekte wie Psyco, PyPy und Unladen Swallow, die verschiedene Ansätze zum Kompilieren von Python-Objektcode in etwas näher an nativem Code verwenden. Es gibt aktive Forschung in diesem Bereich, aber es gibt (noch) keine einfache Antwort.

16

Genau wie (in der typischen Implementierung von) Java oder C#, wird Python zuerst in irgendeine Form von Bytecode kompiliert, abhängig von der Implementierung (CPython verwendet eine spezielle Form seiner eigenen, Jython verwendet JVM genau wie ein typisches Java, IronPython verwendet CLR wie eine typische C# und so weiter) - dieser Bytecode wird dann zur Ausführung durch eine virtuelle Maschine (AKA-Interpreter) weiterverarbeitet, die auch Maschinencode "just in time" erzeugen kann - bekannt als JIT - Wenn und wenn dies gerechtfertigt ist (CLR- und JVM-Implementierungen tun dies oft, kann CPythons eigene virtuelle Maschine dies normalerweise nicht tun, z. B. mit psyco oder Unladen Swallow).

JIT kann sich für ausreichend lange laufende Programme bezahlt machen (wenn Speicher viel billiger ist als CPU-Zyklen), aber möglicherweise nicht (wegen langsamerer Startzeiten und größerem Speicherbedarf), besonders wenn die Typen auch abgeleitet werden müssen oder spezialisiert als Teil der Code-Generierung. Generieren von Maschinencode ohne Typrückschluss oder Spezialisierung ist einfach, wenn das was Sie wollen, z. freeze tut es für Sie, aber es stellt wirklich nicht die Vorteile dar, die "Maschinencodefetischisten" ihm zuschreiben. ZB erhalten Sie eine ausführbare Binärdatei von 1,5 bis 2 MB anstelle einer winzigen "Hallo Welt" .pyc - nicht viel Sinn! -). Diese ausführbare Datei ist eigenständig und als solche verteilbar, aber sie wird nur auf einem sehr spezifischen schmalen Bereich von Betriebssystemen und CPU-Architekturen funktionieren, so dass die Kompromisse in den meisten Fällen ziemlich zweifelhaft sind. Und die Zeit, die für die Vorbereitung der ausführbaren Datei benötigt wird, ist in der Tat ziemlich lang, also wäre es eine verrückte Wahl, diese Betriebsart zur Standardausführung zu machen.

8

Wenn Sie lediglich einen Interpreter durch einen Compiler ersetzen, erhalten Sie keinen so großen Leistungsschub, wie Sie vielleicht für eine Sprache wie Python denken. Wenn die meiste Zeit tatsächlich mit symbolischen Suchvorgängen von Objektmembern in Wörterbüchern verbracht wird, spielt es keine Rolle, ob der Aufruf der Funktion, die eine solche Suche ausführt, interpretiert wird oder ob es sich um nativen Maschinencode handelt durch Nachschlagen Overhead.

Um die Leistung wirklich zu verbessern, benötigen Sie optimierte Compiler. Und die Optimierungstechniken hier unterscheiden sich sehr von denen, die Sie mit C++ haben, oder sogar Java JIT - ein optimierender Compiler für eine dynamisch typisierte/duck-typisierte Sprache wie Python muss einige sehr kreative Typ-Inferenzen machen (einschließlich probabilistischer - dh "90% Chance es ist T "und erzeugt dann effizienten Maschinencode für diesen Fall mit einer Prüfung/Verzweigung davor) und Escape-Analyse. Das ist schwer.

5

Der Aufwand, der erforderlich ist, um einen guten Compiler zum Generieren von systemeigenem Code für eine neue Sprache zu erstellen, ist Staffelung.Kleine Forschungsgruppen dauern typischerweise 5 bis 10 Jahre (Beispiele: SML/NJ, Haskell, Clean, Cecil, lcc, Objective Caml, MLton und viele andere). Und wenn die fragliche Sprache eine Typüberprüfung und andere Entscheidungen zur Laufzeit erfordert, muss ein Compiler-Schreiber viel härter arbeiten, um eine gute native Code-Leistung zu erhalten (für ein hervorragendes Beispiel siehe Arbeiten von Craig Chambers und später Urs Hoelzle) Selbst). Die Leistungssteigerungen, auf die Sie hoffen, sind schwerer zu realisieren als Sie vielleicht denken. Dieses Phänomen erklärt teilweise why so many dynamically typed languages are interpreted. Wie bereits erwähnt, ist ein anständiger Interpreter auch sofort portierbar, während die Portierung von Compilern auf neue Rechnerarchitekturen erhebliche Anstrengungen erfordert (und ein Problem, an dem ich seit über 20 Jahren persönlich arbeite, mit einiger Freizeit für gutes Verhalten). Ein Dolmetscher ist also eine Möglichkeit, ein breites Publikum schnell zu erreichen.

Schließlich, obwohl schnelle Compiler und langsame Interpreter existieren, ist es in der Regel einfacher, den Edit-Translate-Go-Zyklus mit einem Interpreter schneller zu machen. (Für einige schöne Beispiele für schnelle Compiler die oben genannten lcc sowie Ken Thompson go Compiler zu sehen. Ein Beispiel für einen relativ langsamen Interpreter sehen GHCi.

2

REPL. Verwenden Sie es nicht klopfen, bis du es versucht haben. :)

+1

SML/NJ bietet seit über 20 Jahren kompilierte REPL-Software mit nativem Code an ... ebenso wie viele Lisp-Systeme. –

1

Kompilieren Ruby ist mindestens notorisch schwer. Ich arbeite an einem, und als Teil davon schrieb ich einen Blogpost enumerating some of the issues here.

Insbesondere leidet Ruby an einer sehr unklaren (d. H. Nicht existierenden) Grenze zwischen der "Lese" - und "Ausführungs" -Phase des Programms, die es schwierig macht, effizient zu kompilieren. Sie könnten einfach emulieren, was der Dolmetscher tut, aber dann werden Sie nicht viel schneller sehen, also wäre es die Mühe nicht wert. Wenn Sie es effizient kompilieren möchten, müssen Sie mit vielen zusätzlichen Komplikationen rechnen, um die extreme Dynamik von Ruby zu bewältigen.

Die gute Nachricht ist, dass Techniken zur Überwindung dieser sind. Self, Smalltalk und Lisp/Scheme haben sich mit den meisten der gleichen Probleme ziemlich erfolgreich beschäftigt. Aber es braucht Zeit, um es zu durchforsten und herauszufinden, wie es mit Ruby funktionieren kann. Es hilft auch nicht, dass Ruby eine sehr komplizierte Grammatik hat.

1

Raw compute Leistung ist wahrscheinlich kein Ziel der meisten interpretierten Sprachen. Interpretierte Sprachen befassen sich in der Regel mehr mit der Produktivität von Programmierern als mit roher Geschwindigkeit. In den meisten Fällen sind diese Sprachen ausreichend schnell genug für die Aufgaben, die die Sprachen erfüllen sollen.

Angesichts der Tatsache, und das nur über die einzigen Vorteile eines Compilers sind Typprüfung (schwierig in einer dynamischen Sprache zu tun) und Geschwindigkeit, gibt es nicht viel Anreiz, Compiler für die meisten interpretierten Sprachen zu schreiben.

Verwandte Themen