Java "Virtual Machine" vs. Python "Interpreter"?


207

Es scheint selten, von einer Python "virtuellen Maschine" zu lesen, während in Java "virtuelle Maschine" die ganze Zeit verwendet wird.

Beide interpretieren Bytecodes; Warum sollte man eine virtuelle Maschine und die andere einen Dolmetscher nennen?

Antworten:


137

Eine virtuelle Maschine ist eine virtuelle Computerumgebung mit einem bestimmten Satz atomarer, genau definierter Anweisungen, die unabhängig von einer bestimmten Sprache unterstützt werden. Sie wird im Allgemeinen als Sandbox für sich betrachtet. Die VM ist analog zu einem Befehlssatz einer bestimmten CPU und arbeitet tendenziell auf einer grundlegenderen Ebene mit sehr grundlegenden Bausteinen solcher Befehle (oder Bytecodes), die vom nächsten unabhängig sind. Ein Befehl wird deterministisch nur basierend auf dem aktuellen Status der virtuellen Maschine ausgeführt und hängt zu diesem Zeitpunkt nicht von Informationen an anderer Stelle im Befehlsstrom ab.

Ein Interpreter hingegen ist insofern ausgefeilter, als er darauf zugeschnitten ist, einen Stream einer Syntax einer bestimmten Sprache und eines bestimmten Grammatikers zu analysieren, der im Kontext der umgebenden Token dekodiert werden muss. Sie können nicht jedes Byte oder sogar jede Zeile einzeln betrachten und wissen genau, was als nächstes zu tun ist. Die Token in der Sprache können nicht isoliert betrachtet werden, wie dies bei den Anweisungen (Bytecodes) einer VM der Fall ist.

Ein Java-Compiler konvertiert die Java-Sprache in einen Bytecode-Stream, der sich nicht von einem C-Compiler unterscheidet. Er konvertiert C-Language-Programme in Assembler-Code. Ein Interpreter hingegen konvertiert das Programm nicht wirklich in eine genau definierte Zwischenform, sondern nimmt nur die Programmaktionen als eine Frage des Interpretationsprozesses der Quelle.

Ein weiterer Test für den Unterschied zwischen einer VM und einem Interpreter besteht darin, ob Sie sie als sprachunabhängig betrachten. Was wir als Java VM kennen, ist nicht wirklich Java-spezifisch. Sie können einen Compiler aus anderen Sprachen erstellen, der zu Bytecodes führt, die auf der JVM ausgeführt werden können. Andererseits denke ich nicht, dass wir wirklich daran denken würden, eine andere Sprache als Python in Python zu "kompilieren", um sie vom Python-Interpreter zu interpretieren.

Aufgrund der Raffinesse des Interpretationsprozesses kann dies ein relativ langsamer Prozess sein. Insbesondere das Parsen und Identifizieren der Sprach-Token usw. und das Verstehen des Kontextes der Quelle, um den Ausführungsprozess innerhalb des Interpreters durchführen zu können. Um solche interpretierten Sprachen zu beschleunigen, können wir hier Zwischenformen von vorgeparstem, vor-tokenisiertem Quellcode definieren, der leichter direkt interpretiert werden kann. Diese Art von binärer Form wird zur Ausführungszeit immer noch interpretiert. Sie beginnt nur mit einer viel weniger lesbaren Form, um die Leistung zu verbessern. Die Logik, die dieses Formular ausführt, ist jedoch keine virtuelle Maschine, da diese Codes immer noch nicht isoliert betrachtet werden können - der Kontext der umgebenden Token spielt immer noch eine Rolle, sie befinden sich gerade in einer anderen, computereffizienteren Form.


7
Ich hatte den Eindruck, dass Python Bytecode, pyc, generiert hat oder dass das, worauf Sie sich beziehen, "dazu beiträgt, solche interpretierten Sprachen zu beschleunigen. Hier können wir Zwischenformen von vorgeparstem, vor-tokenisiertem Quellcode definieren, die mehr sind leicht direkt interpretiert. "
James McMahon

32
@InSciTek Jeff: Aus Ihrer Antwort geht nicht hervor, ob Sie wissen, dass Python auch eine virtuelle Maschine verwendet.
Zot

3
@TZ - Die beliebte Python-Implementierung ist ein Python-Compiler mit einer Backside-VM. Im interaktiven Modus ist es ein bisschen hybride mit einem Interpreter-Frontend und einem Compiler-Backend. Dies sind jedoch Implementierungsoptionen. Ich habe versucht, den Unterschied zwischen dem Konzept von VM und Interpreter zu beschreiben
Tall Jeff

8
On the other hand, I don't think we would really think of "compiling" some other language other than Python into Python for interpretation by the Python interpreter.Es ist möglich, eine Sprache zu schreiben, die in Python-Bytecode kompiliert werden kann, genau wie Scala in Java-Bytecode kompiliert wird. Im interaktiven Modus kompiliert die interaktive Shell von Python Ihren eingegebenen Befehl in Bytecode und führt diesen Bytecode aus. Sie können Ihre eigene Shell mit eval und exec schreiben und die integrierte Funktion compile () verwenden, um eine Zeichenfolge in Bytecode umzuwandeln.
Lie Ryan

4
@Lie Ryan ja, aber es wird nicht offiziell unterstützt wie bei der JVM. In Python ist Bytecode ein undokumentiertes Implementierungsdetail.
Antimon

159

In diesem Beitrag bezieht sich "virtuelle Maschine" auf virtuelle Prozessmaschinen, nicht auf virtuelle Systemmaschinen wie Qemu oder Virtualbox. Eine virtuelle Prozessmaschine ist einfach ein Programm, das eine allgemeine Programmierumgebung bereitstellt - ein Programm, das programmiert werden kann.

Java hat einen Interpreter sowie eine virtuelle Maschine, und Python hat eine virtuelle Maschine sowie einen Interpreter. Der Grund, warum "virtuelle Maschine" in Java häufiger verwendet wird und "Interpreter" in Python häufiger verwendet wird, hat viel mit dem Hauptunterschied zwischen den beiden Sprachen zu tun: statische Typisierung (Java) und dynamische Typisierung (Python). In diesem Zusammenhang bezieht sich "Typ" auf primitive Datentypen - Typen, die die Speichergröße der Daten im Speicher vorschlagen. Die Java Virtual Machine hat es einfach. Der Programmierer muss den primitiven Datentyp jeder Variablen angeben. Dies liefert ausreichende Informationen, damit Java-Bytecode nicht nur von der virtuellen Java-Maschine interpretiert und ausgeführt, sondern sogar in Maschinenanweisungen kompiliert werden kann. Die virtuelle Python-Maschine ist insofern komplexer, als sie die zusätzliche Aufgabe übernimmt, vor der Ausführung jeder Operation eine Pause einzulegen, um die primitiven Datentypen für jede Variable oder Datenstruktur zu bestimmen, die an der Operation beteiligt ist. Python befreit den Programmierer vom Denken in primitiven Datentypen und ermöglicht es, Operationen auf einer höheren Ebene auszudrücken. Der Preis für diese Freiheit ist die Leistung. "Interpreter" ist der bevorzugte Begriff für Python, da er zur Überprüfung von Datentypen angehalten werden muss und die vergleichsweise präzise Syntax dynamisch typisierter Sprachen für interaktive Schnittstellen gut geeignet ist. Es gibt keine technische Barriere beim Erstellen einer interaktiven Java-Schnittstelle, aber der Versuch, statisch typisierten Code interaktiv zu schreiben, wäre mühsam, daher wird dies einfach nicht so gemacht.

In der Java-Welt stiehlt die virtuelle Maschine die Show, weil sie Programme ausführt, die in einer Sprache geschrieben sind, die tatsächlich in Maschinenanweisungen kompiliert werden kann, und das Ergebnis ist Geschwindigkeit und Ressourceneffizienz. Java-Bytecode kann von der virtuellen Java-Maschine ausgeführt werden, wobei die Leistung relativ gesehen der von kompilierten Programmen nahe kommt. Dies ist auf das Vorhandensein primitiver Datentypinformationen im Bytecode zurückzuführen. Die Java Virtual Machine ordnet Java einer eigenen Kategorie zu:

tragbare interpretierte statisch typisierte Sprache

Das nächstgelegene ist LLVM, aber LLVM arbeitet auf einer anderen Ebene:

tragbare interpretierte Assemblersprache

Der Begriff "Bytecode" wird sowohl in Java als auch in Python verwendet, aber nicht alle Bytecodes sind gleich. Bytecode ist nur der Oberbegriff für Zwischensprachen, die von Compilern / Interpreten verwendet werden. Sogar C-Compiler wie gcc verwenden eine Zwischensprache (oder mehrere) , um die Arbeit zu erledigen. Java-Bytecode enthält Informationen zu primitiven Datentypen, Python-Bytecode jedoch nicht. In dieser Hinsicht ist die virtuelle Maschine von Python (und Bash, Perl, Ruby usw.) grundlegend langsamer als die virtuelle Maschine von Java, oder sie hat einfach mehr Arbeit zu erledigen. Es ist nützlich zu überlegen, welche Informationen in verschiedenen Bytecode-Formaten enthalten sind:

  • llvm: CPU-Register
  • Java: primitive Datentypen
  • Python: benutzerdefinierte Typen

Um eine reale Analogie zu ziehen: LLVM arbeitet mit Atomen, die Java Virtual Machine arbeitet mit Molekülen und die Python Virtual Machine arbeitet mit Materialien. Da sich schließlich alles in subatomare Partikel zerlegen muss (reale Maschinenoperationen), hat die virtuelle Python-Maschine die komplexeste Aufgabe.

Dolmetscher / Compiler statisch typisierter Sprachen haben einfach nicht das gleiche Gepäck wie Dolmetscher / Compiler dynamisch typisierter Sprachen. Programmierer statisch typisierter Sprachen müssen die Lücke schließen, für die sich die Leistung auszahlt. So wie alle nichtdeterministischen Funktionen insgeheim deterministisch sind, sind auch alle dynamisch typisierten Sprachen heimlich statisch typisiert. Leistungsunterschiede zwischen den beiden Sprachfamilien sollten sich daher zu dem Zeitpunkt ausgleichen, an dem Python seinen Namen in HAL 9000 ändert.

Die virtuellen Maschinen dynamischer Sprachen wie Python implementieren eine idealisierte logische Maschine und entsprechen nicht unbedingt einer realen physischen Hardware. Im Gegensatz dazu ähnelt die virtuelle Java-Maschine in ihrer Funktionalität eher einem klassischen C-Compiler, außer dass anstelle der Ausgabe von Maschinenanweisungen integrierte Routinen ausgeführt werden. In Python ist eine Ganzzahl ein Python-Objekt mit einer Reihe von Attributen und Methoden. In Java ist ein int eine bestimmte Anzahl von Bits, normalerweise 32. Es ist kein wirklich fairer Vergleich. Python-Ganzzahlen sollten wirklich mit der Java Integer-Klasse verglichen werden. Der primitive Datentyp "int" von Java kann mit nichts in der Python-Sprache verglichen werden, da der Python-Sprache diese Primitivschicht einfach fehlt, ebenso wie der Python-Bytecode.

Da Java-Variablen explizit typisiert werden, kann man davon ausgehen, dass sich die Jython- Leistung im selben Ballpark wie cPython befindet . Andererseits ist eine in Python implementierte virtuelle Java-Maschine fast garantiert langsamer als Schlamm. Und erwarten Sie nicht, dass Ruby, Perl usw. besser abschneiden. Sie waren nicht dafür ausgelegt. Sie wurden für "Scripting" entwickelt, wie das Programmieren in einer dynamischen Sprache genannt wird.

Jede Operation, die in einer virtuellen Maschine stattfindet, muss schließlich auf reale Hardware treffen. Virtuelle Maschinen enthalten vorkompilierte Routinen, die allgemein genug sind, um eine beliebige Kombination logischer Operationen auszuführen. Eine virtuelle Maschine gibt möglicherweise keine neuen Maschinenanweisungen aus, führt jedoch ihre eigenen Routinen immer wieder in willkürlich komplexen Sequenzen aus. Die virtuelle Java-Maschine, die virtuelle Python-Maschine und alle anderen virtuellen Allzweckmaschinen sind in dem Sinne gleich, dass sie dazu gebracht werden können, jede Logik auszuführen, die Sie sich vorstellen können, aber sie unterscheiden sich hinsichtlich der Aufgaben, die sie haben übernehmen und welche Aufgaben sie dem Programmierer überlassen.

Psyco for Python ist keine vollständige virtuelle Python-Maschine, sondern ein Just-in-Time-Compiler, der die reguläre virtuelle Python-Maschine an Stellen entführt, an denen sie glaubt, einige Codezeilen kompilieren zu können - hauptsächlich Schleifen, bei denen der primitive Typ einiger davon angenommen wird Die Variable bleibt konstant, auch wenn sich der Wert mit jeder Iteration ändert. In diesem Fall kann auf die unaufhörliche Typbestimmung der regulären virtuellen Maschine verzichtet werden. Sie müssen jedoch ein wenig vorsichtig sein, damit Sie den Typ nicht unter Psycos Füßen herausziehen. Pysco weiß jedoch normalerweise, dass es einfach auf die normale virtuelle Maschine zurückgreifen muss, wenn es nicht ganz sicher ist, dass sich der Typ nicht ändert.

Die Moral der Geschichte ist, dass primitive Datentypinformationen für einen Compiler / eine virtuelle Maschine wirklich hilfreich sind.

Um alles in die richtige Perspektive zu rücken, betrachten Sie Folgendes: Ein Python-Programm, das von einem Python-Interpreter / einer virtuellen Maschine ausgeführt wird, die in Java implementiert ist und auf einem Java-Interpreter / einer virtuellen Maschine ausgeführt wird, die / die in LLVM implementiert ist und in einer virtuellen qemu-Maschine ausgeführt wird, die auf einem iPhone ausgeführt wird.

Permalink


1
trying to write any statically-typed code interactively would be tedious. Wenn Sie OCaml und Haskell kennen, werden Sie feststellen, dass dies nicht der Fall ist, da es sich um sehr präzise statisch typisierte Sprachen handelt.
Matthias Braun

@MatthiasBraun Ich kann zustimmen, dass diese funktionalen Sprachen präzisen Code produzieren, aber das bedeutet nicht unbedingt, dass sie für den interaktiven Modus gut geeignet sind. Wenn OCaml und Haskell wie Lisp dynamisch typisiert würden, würden sie für den interaktiven Modus, wie ich annehme, besser funktionieren.
Bomben

58

Wahrscheinlich ist ein Grund für die unterschiedliche Terminologie, dass man normalerweise daran denkt, den von Menschen lesbaren Quellcode des Python-Interpreters zu füttern und sich nicht um Bytecode und all das zu kümmern.

In Java müssen Sie explizit zu Bytecode kompilieren und dann nur den Bytecode und nicht den Quellcode auf der VM ausführen.

Obwohl Python eine virtuelle Maschine unter dem Deckmantel verwendet, kann man aus Anwendersicht dieses Detail die meiste Zeit ignorieren.


1
Genau. Dieser Unterschied in der Terminologie hängt wirklich von der Erfahrung des Endbenutzers (Entwicklers) ab. Es hat nichts mit echten technischen Unterschieden zu tun, da die technische Linie so unglaublich verschwommen ist, dass sie fast nicht mehr existiert.
Cody Brocious

1
+1: Und - was noch wichtiger ist - worum geht es? Welches Programm können Sie aufgrund dieser Unterscheidung nicht schreiben? Welcher Stack-Traceback verwirrt Sie? Welche Bibliothek scheint nicht richtig zu funktionieren?
S.Lott

@ S.Lott Weil es immer gut ist, mit Kollegen Streit zu gewinnen. ;)
Qix - MONICA wurde

16

Interpreter übersetzt den Quellcode in eine effiziente Zwischendarstellung (Code) und führt diese sofort aus.

Virtual Machine führt explizit gespeicherten vorkompilierten Code aus, der von einem Compiler erstellt wurde, der Teil des Interpretersystems ist.

Ein sehr wichtiges Merkmal einer virtuellen Maschine ist, dass die darin ausgeführte Software auf die von der virtuellen Maschine bereitgestellten Ressourcen beschränkt ist. Genau genommen kann es nicht aus seiner virtuellen Welt ausbrechen. Denken Sie an die sichere Ausführung von Remote-Code, Java Applets.

Im Fall von Python würde der Mechanismus , wenn wir Pyc- Dateien behalten , wie im Kommentar dieses Beitrags erwähnt, eher einer VM ähneln , und dieser Bytecode wird schneller ausgeführt - er würde immer noch interpretiert, aber aus einer viel computerfreundlicheren Form . Wenn wir dies als Ganzes betrachten, ist PVM ein letzter Schritt von Python Interpreter.

Die Quintessenz ist, wenn wir Python Interpreter verweisen, bedeutet dies, dass wir es als Ganzes verweisen, und wenn wir PVM sagen, bedeutet dies, dass wir nur über einen Teil von Python Interpreter sprechen, eine Laufzeitumgebung. Ähnlich wie bei Java verweisen wir auf verschiedene Teile differentyl, JRE, JVM, JDK usw.

Weitere Informationen finden Sie unter Wikipedia-Eintrag: Interpreter und Virtuelle Maschine . Noch einer hier . Hier finden Sie den Vergleich der virtuellen Anwendungsmaschinen . Es hilft beim Verständnis des Unterschieds zwischen Compilern, Interpreten und VMs.


12

Der Begriff Interpreter ist ein Legacy-Begriff, der auf frühere Shell-Skriptsprachen zurückgeht. Da sich "Skriptsprachen" zu voll funktionsfähigen Sprachen entwickelt haben und die entsprechenden Plattformen komplexer und umfangreicher geworden sind, ist die Unterscheidung zwischen einer virtuellen Maschine und einem Interpreter (im Sinne von Python) sehr gering oder nicht vorhanden.

Der Python-Interpreter funktioniert weiterhin wie ein Shell-Skript, da er ohne separaten Kompilierungsschritt ausgeführt werden kann. Darüber hinaus sind die Unterschiede zwischen Pythons Interpreter (oder Perl oder Ruby's) und Javas virtueller Maschine hauptsächlich Implementierungsdetails. (Man könnte argumentieren, dass Java eine vollständigere Sandbox als Python ist, aber beide bieten letztendlich Zugriff auf die zugrunde liegende Architektur über eine native C-Schnittstelle.)


1
Es gibt Java-Shells, die Java-Code ohne separate (vom Benutzer sichtbare) Kompilierungsschritte ausführen können.
Lie Ryan

1
Gib mir den Namen: D
Maciej Nowicki

11

Um eine tiefe Antwort auf die Frage " Warum Java Virtual Machine, aber Python-Interpreter? " Zu geben, versuchen wir, zum Ausgangspunkt der Diskussion auf das Gebiet der Kompilierungstheorie zurückzukehren.

Der typische Prozess der Programmkompilierung umfasst die folgenden Schritte:

  1. Lexikalische Analyse . Teilt den Programmtext in aussagekräftige "Wörter" auf, die als Token bezeichnet werden (im Rahmen des Prozesses werden alle Kommentare, Leerzeichen, Zeilenumbrüche usw. entfernt, da sie das Programmverhalten nicht beeinflussen). Das Ergebnis ist ein geordneter Strom von Token.
  2. Syntaxanalyse . Erstellt den sogenannten Abstract Syntax Tree (AST) aus dem Token-Stream. AST stellt Beziehungen zwischen Token her und definiert infolgedessen eine Reihenfolge der Bewertung des Programms.
  3. Semantische Analyse . Überprüft die semantische Korrektheit des AST anhand von Informationen zu Typen und einer Reihe semantischer Regeln der Programmiersprache. ( a = b + cIst abeispielsweise aus Sicht der Syntax eine korrekte Aussage, aus semantischer Sicht jedoch völlig falsch, wenn sie als konstantes Objekt deklariert wurde.)
  4. Zwischencodegenerierung . Serialisiert AST in den linear geordneten Strom maschinenunabhängiger "primitiver" Operationen. Tatsächlich durchläuft der Codegenerator AST und protokolliert die Reihenfolge der Auswertungsschritte. Als Ergebnis erhalten wir aus der baumartigen Darstellung des Programms eine viel einfachere listenartige Darstellung, in der die Reihenfolge der Programmevaluierung erhalten bleibt.
  5. Maschinencodegenerierung . Das Programm in Form eines maschinenunabhängigen "primitiven" Bytecodes wird in Maschinencode einer bestimmten Prozessorarchitektur übersetzt.

OK. Definieren wir nun die Begriffe.

Interpreter , im klassischen Sinne des Wortes, übernimmt die Ausführung auf dem Grundlage des Auswertungsprogramm auf Basis von AST direkt aus dem Programm erzeugten Text . In diesem Fall wird ein Programm in Form von Quellcode verteilt und der Interpreter wird häufig dynamisch (Anweisung für Anweisung oder Zeile für Zeile) durch Programmtext gespeist. Für jede Eingabeanweisung erstellt der Interpreter seinen AST und wertet ihn sofort aus, indem er den "Status" des Programms ändert. Dies ist ein typisches Verhalten, das durch Skriptsprachen demonstriert wird. Betrachten Sie zum Beispiel Bash, Windows CMD usw. Konzeptionell geht Python auch so vor.

Wenn wir den AST-basierten Ausführungsschritt bei der Erzeugung eines maschinenunabhängigen binären Bytecode-Zwischenschritts im Interpreter ersetzen, teilen wir den gesamten Prozess der Programmausführung in zwei separate Phasen auf: Kompilierung und Ausführung. In diesem Fall wird das, was zuvor ein Interpreter war, zu einem Bytecode-Compiler, der das Programm von der Form des Textes in eine binäre Form umwandelt . Dann wird das Programm in dieser binären Form verteilt, jedoch nicht in Form von Quellcode. Auf der Benutzermaschine wird dieser Bytecode in eine neue Entität eingespeist - die virtuelle Maschine , die diesen Bytecode tatsächlich interpretiert. Aus diesem Grund werden virtuelle Maschinen auch als Bytecode-Interpreter bezeichnet . Aber lenken Sie Ihre Aufmerksamkeit hier! Ein klassischer Dolmetscher ist aTextinterpreter , aber eine virtuelle Maschine ist ein Binärinterpreter ! Dies ist ein Ansatz von Java und C #.

Wenn wir schließlich die Maschinencodegenerierung zum Bytecode-Compiler hinzufügen, erzielen wir ein Ergebnis, das wir als klassischen Compiler bezeichnen . Ein klassischer Compiler konvertiert den Programmquellcode in den Maschinencode eines bestimmten Prozessors. Dieser Maschinencode kann dann ohne zusätzliche Vermittlung direkt auf dem Zielprozessor ausgeführt werden (ohne irgendeine Art von Interpreter weder Textinterpreter noch Binärinterpreter).

Kehren wir nun zur ursprünglichen Frage zurück und betrachten Java gegen Python.

Java wurde ursprünglich so konzipiert, dass möglichst wenige Implementierungsabhängigkeiten bestehen. Sein Design basiert auf dem Prinzip "einmal schreiben, überall ausführen" (WORA). Um es zu implementieren, wurde Java ursprünglich als Programmiersprache entwickelt, die in maschinenunabhängigen binären Bytecode kompiliert wird , der dann auf allen Plattformen ausgeführt werden kann, die Java unterstützen, ohne dass eine Neukompilierung erforderlich ist. Sie können an Java wie an WORA-basiertes C ++ denken . Tatsächlich ist Java näher an C ++ als an den Skriptsprachen wie Python . Aber im Gegensatz zu C ++ , Javawurde entwickelt, um in binären Bytecode kompiliert zu werden, der dann in der Umgebung der virtuellen Maschine ausgeführt wird , während C ++ entworfen wurde, um in Maschinencode kompiliert und dann direkt vom Zielprozessor ausgeführt zu werden.

Python wurde ursprünglich als eine Art Skript-Programmiersprache entwickelt, die Skripte interpretiert (Programme in Form des Textes , der gemäß den Regeln der Programmiersprache geschrieben wurde). Aus diesem Grund hat Python zunächst eine dynamische Interpretation einzeiliger Befehle oder Anweisungen unterstützt, wie dies bei Bash oder Windows CMD der Fall ist. Aus dem gleichen Grunde, erste Implementierungen von Python hatten keine Art von Bytecode - Compiler und virtueller Maschinen zur Ausführung eines solchen Bytecode nach innen, aber von Anfang an Python hatte erforderlich Dolmetscher der in der Lage ist , zu verstehen und Python - Programm auswerten Textes .

Aus diesem Grund sprachen Java- Entwickler in der Vergangenheit eher über Java Virtual Machine (da Java ursprünglich als Paket aus Java- Bytecode-Compiler und Bytecode-Interpreter ( JVM ) geliefert wurde ), und Python- Entwickler sprachen eher über Python- Interpreter (weil Python dies anfangs getan hat) keine virtuelle Maschine und war eine Art klassischen Text - Interpreter das Programm ausführt Text direkt ohne jede Art von Zusammenstellung oder Umwandlung in irgendeiner Form von Binärcode).

Derzeit hat Python auch die virtuelle Maschine unter der Haube und kann Python-Bytecode kompilieren und interpretieren. Und diese Tatsache macht eine zusätzliche Investition in die Verwirrung " Warum Java Virtual Machine, aber Python-Interpreter?und dass Programme genau das gleiche Verhalten zeigen und aus der gleichen Eingabe gleich die gleiche Ausgabe erzeugen. Der einzige beobachtbare Unterschied ist die Geschwindigkeit der Programmausführung und die vom Interpreter verbrauchte Speichermenge. Daher ist die virtuelle Maschine in Python kein unvermeidbarer Bestandteil des Sprachdesigns, sondern lediglich eine optionale Erweiterung des wichtigsten Python-Interpreters.

Java kann auf ähnliche Weise betrachtet werden. Java unter der Haube hat einen JIT-Compiler und kann Methoden der Java-Klasse selektiv in Maschinencode der Zielplattform kompilieren und dann direkt ausführen. Aber! Java verwendet weiterhin die Bytecode-Interpretation als primäre Methode zur Ausführung von Java-Programmen. Wie Python-Implementierungen, die virtuelle Maschinen unter der Haube ausschließlich als Optimierungstechnik nutzen, verwenden die virtuellen Java-Maschinen Just-In-Time-Compiler ausschließlich zu Optimierungszwecken. Ebenso nur aufgrund der Tatsache, dass die direkte Ausführung des Maschinencodes mindestens zehnmal schneller ist als die Interpretation des Java-Bytecodes. Und wie im Fall von Python ist das Vorhandensein eines JIT-Compilers unter der Haube von JVM sowohl für Java-Sprachdesigner als auch für Java-Programmentwickler absolut transparent. Dieselbe Java-Programmiersprache kann von JVM mit und ohne JIT-Compiler implementiert werden. Auf die gleiche Weise können dieselben Programme in JVMs mit und ohne JIT ausgeführt werden, und dieselben Programme zeigen genau dasselbe Verhalten und erzeugen auf beiden JVMs (mit und ohne JIT) die gleiche Ausgabe aus der gleichen Eingabe. Und wie im Fall von Python besteht der einzige beobachtbare Unterschied zwischen ihnen in der Ausführungsgeschwindigkeit und in der von JVM verbrauchten Speichermenge. Und schließlich ist JIT in Java, wie im Fall von Python, kein unvermeidbarer Bestandteil des Sprachdesigns, sondern nur eine optionale Erweiterung der wichtigsten JVM-Implementierungen. und die gleichen Programme zeigen genau das gleiche Verhalten und erzeugen auf beiden JVMs (mit und ohne JIT) gleich die gleiche Ausgabe aus der gleichen Eingabe. Und wie im Fall von Python besteht der einzige beobachtbare Unterschied zwischen ihnen in der Ausführungsgeschwindigkeit und in der von JVM verbrauchten Speichermenge. Und schließlich ist JIT in Java, wie im Fall von Python, kein unvermeidbarer Bestandteil des Sprachdesigns, sondern nur eine optionale Erweiterung der wichtigsten JVM-Implementierungen. und die gleichen Programme zeigen genau das gleiche Verhalten und erzeugen auf beiden JVMs (mit und ohne JIT) gleich die gleiche Ausgabe aus der gleichen Eingabe. Und wie im Fall von Python besteht der einzige beobachtbare Unterschied zwischen ihnen in der Ausführungsgeschwindigkeit und in der von JVM verbrauchten Speichermenge. Und schließlich ist JIT in Java, wie im Fall von Python, kein unvermeidbarer Bestandteil des Sprachdesigns, sondern nur eine optionale Erweiterung der wichtigsten JVM-Implementierungen.

Unter dem Gesichtspunkt des Entwurfs und der Implementierung von virtuellen Maschinen von Java und Python unterscheiden sie sich erheblich, während (Aufmerksamkeit!) Beide weiterhin virtuelle Maschinen bleiben. JVM ist ein Beispiel für eine virtuelle Maschine auf niedriger Ebene mit einfachen Grundoperationen und hohen Versandkosten für Befehle. Python wiederum ist eine virtuelle Maschine auf hoher Ebene, für die Anweisungen ein komplexes Verhalten aufweisen und die Kosten für den Versand von Anweisungen nicht so hoch sind. Java arbeitet mit einer sehr niedrigen Abstraktionsstufe. JVM arbeitet mit dem kleinen, genau definierten Satz primitiver Typen und weist eine sehr enge Übereinstimmung (normalerweise eins zu eins) zwischen Bytecode-Anweisungen und nativen Maschinencode-Anweisungen auf. Im Gegensatz dazu arbeitet die virtuelle Python-Maschine auf einer hohen Abstraktionsebene, arbeitet mit komplexen Datentypen (Objekten) und unterstützt Ad-hoc-Polymorphismus. Bytecode-Anweisungen legen komplexes Verhalten offen, das durch eine Reihe mehrerer nativer Maschinencode-Anweisungen dargestellt werden kann. Beispielsweise unterstützt Python unbegrenzte Bereichsmathematik. Daher ist Python VM gezwungen, lange Arithmetiken für potenziell große Ganzzahlen auszunutzen, bei denen das Ergebnis der Operation das Maschinenwort überlaufen kann. Daher kann ein Bytecode-Befehl für Arithmetik in Python in den Funktionsaufruf in Python VM verfügbar gemacht werden, während in JVM-Arithmetikoperationen in einfache Operationen verfügbar gemacht werden, die durch einen oder wenige native Maschinenbefehle ausgedrückt werden. Daher ist Python VM gezwungen, lange Arithmetiken für potenziell große Ganzzahlen auszunutzen, bei denen das Ergebnis der Operation das Maschinenwort überlaufen kann. Daher kann ein Bytecode-Befehl für Arithmetik in Python in den Funktionsaufruf in Python VM verfügbar gemacht werden, während in JVM-Arithmetikoperationen in einfache Operationen verfügbar gemacht werden, die durch einen oder wenige native Maschinenbefehle ausgedrückt werden. Daher ist Python VM gezwungen, lange Arithmetiken für potenziell große Ganzzahlen auszunutzen, bei denen das Ergebnis der Operation das Maschinenwort überlaufen kann. Daher kann ein Bytecode-Befehl für Arithmetik in Python in den Funktionsaufruf in Python VM verfügbar gemacht werden, während in JVM-Arithmetikoperationen in einfache Operationen verfügbar gemacht werden, die durch einen oder wenige native Maschinenbefehle ausgedrückt werden.

Infolgedessen können wir die nächsten Schlussfolgerungen ziehen. Java Virtual Machine, aber Python-Interpreter ist weil:

  1. Der Begriff der virtuellen Maschine setzt eine binäre Bytecode-Interpretation voraus, während der Begriff Interpreter eine Programmtextinterpretation voraussetzt.
  2. In der Vergangenheit wurde Java für die Interpretation von binärem Bytecode entworfen und implementiert, und Python wurde ursprünglich für die Interpretation von Programmtexten entworfen und implementiert. Daher ist der Begriff "Java Virtual Machine" historisch und in der Java-Community gut etabliert. Ebenso ist der Begriff "Python-Interpreter" historisch und in der Python-Community gut etabliert. Die Menschen neigen dazu, die Tradition zu verlängern und dieselben Begriffe zu verwenden, die lange zuvor verwendet wurden.
  3. Schließlich ist derzeit für Java die Interpretation von binärem Bytecode eine primäre Methode zur Programmausführung, während die JIT-Kompilierung nur eine optionale und transparente Optimierung ist. Derzeit ist die Programmtextinterpretation für Python eine Hauptmethode für die Ausführung von Python-Programmen, während die Kompilierung in Python VM-Bytecode nur eine optionale und transparente Optimierung darstellt.

Daher haben sowohl Java als auch Python virtuelle Maschinen, die binäre Bytecode-Interpreter sind, was zu Verwirrung führen kann, z. B. " Warum Java Virtual Machine, aber Python-Interpreter?"". Der entscheidende Punkt hierbei ist, dass eine virtuelle Maschine für Python kein primäres oder notwendiges Mittel zur Programmausführung ist; sie ist nur eine optionale Erweiterung des klassischen Textinterpreters. Andererseits ist eine virtuelle Maschine ein Kern und unvermeidlich Teil des Java-Programms zur Programmausführung. Die statische oder dynamische Auswahl der Typisierung für das Design der Programmiersprache wirkt sich hauptsächlich nur auf die Abstraktionsstufe der virtuellen Maschine aus, bestimmt jedoch nicht, ob eine virtuelle Maschine benötigt wird oder nicht. Sprachen, die beide Typisierungssysteme verwenden, können zum Kompilieren entworfen werden , interpretiert oder in der Umgebung der virtuellen Maschine ausgeführt, abhängig von ihrem gewünschten Ausführungsmodell.


2
Dies sollte meiner Meinung nach als offizielle Antwort gewählt werden.
Ravikanth Andhavarapu

Die offizielle Antwort sollte JA lauten, da "sowohl Java als auch Python virtuelle Maschinen haben, die binäre Bytecode-Interpreter sind". Zeitraum.
stuartw

10

Es gibt keinen wirklichen Unterschied zwischen ihnen, die Leute folgen einfach den Konventionen, die die Schöpfer gewählt haben.


3
Ich werde dir hier einen Knochen werfen, da ich denke, dass dies wahrscheinlich die wahre Antwort ist und du wegen fehlender Teile runtergestimmt wurdest.
Wikingerben

3

Vergessen Sie nicht, dass Python JIT-Compiler für x86 zur Verfügung hat, was das Problem weiter verwirrt. (Siehe Psyco).

Eine strengere Interpretation einer "interpretierten Sprache" wird nur nützlich, wenn Leistungsprobleme der VM diskutiert werden. Beispielsweise wurde (wird?) Ruby im Vergleich zu Python als langsamer angesehen, da es sich im Gegensatz zu Python - in anderen - um eine interpretierte Sprache handelt Worte, Kontext ist alles.


1
Das ist falsch. Erstens gibt es keine "interpretierte Sprache". Ob eine Implementierung einen Compiler oder einen Interpreter verwendet, ist kein Merkmal der Sprache, sondern der Implementierung. Zweitens ist von den rund 13 Ruby-Implementierungen genau 1 ein Interpreter, alle anderen haben Compiler.
Jörg W Mittag

2
Drittens ist Ruby nicht langsam. Keine Sprache ist langsam, denn Geschwindigkeit ist kein Merkmal der Sprache, sondern der Sprachimplementierung. Von den rund 13 Ruby-Implementierungen sind einige langsamer als einige der 7 Python-Implementierungen, andere sind schneller.
Jörg W Mittag

Ich denke, er vergleicht hier die Standardimplementierungen Jörg. CPython und Ruby (ich denke, die offizielle Implementierung heißt nur Ruby).
James McMahon

Während Arafangion sich möglicherweise auf die "Standard" -Implementierungen bezieht, hätte er dies sagen sollen. Ich bin ein Pythonist, aber ich hasse jede Aussage der Form "Sprache X ist langsam", da ich Jörg in Bezug auf Implementierungen zustimme.
Zot

1
Genau deshalb habe ich "war (ist?)" Und insbesondere den Begriff "langsamer" gesagt. Nirgendwo habe ich gesagt, dass Ruby an sich langsam ist.
Arafangion

2

Python kann Code interpretieren, ohne ihn zu Bytecode zu kompilieren. Java kann nicht .

Python ist eine interpretierte Sprache im Gegensatz zu einer kompilierten, obwohl die Unterscheidung aufgrund des Vorhandenseins des Bytecode-Compilers verschwommen sein kann. Dies bedeutet, dass Quelldateien direkt ausgeführt werden können, ohne explizit eine ausführbare Datei zu erstellen, die dann ausgeführt wird.

(aus der Dokumentation).

In Java, jede einzelne Datei muss zu einer kompiliert werden .classDatei, die dann auf der JVM läuft. Im Gegenteil, Python wird von Ihrem Hauptskript importiert, um die spätere Verwendung dieser Dateien zu beschleunigen.

Im typischen Fall wird der größte Teil des Python-Codes (zumindest CPython) auf einem emulierten Stack-Computer ausgeführt, der nahezu identische Anweisungen wie die JVM enthält, sodass es keinen großen Unterschied gibt.

Der wahre Grund für die Unterscheidung ist jedoch, dass sich Java von Anfang an als "portabler, ausführbarer Bytecode" und Python als dynamische, interpretierte Sprache mit einer REPL gebrandmarkt hat. Namen bleiben!


0

Zunächst sollten Sie verstehen, dass Programmieren oder Informatik im Allgemeinen keine Mathematik ist und wir für die meisten Begriffe, die wir häufig verwenden, keine strengen Definitionen haben.

Nun zu Ihrer Frage:

Was ist ein Dolmetscher (in der Informatik)

Es übersetzt den Quellcode nach der kleinsten ausführbaren Einheit und führt diese Einheit dann aus.

Was ist eine virtuelle Maschine?

Im Fall von JVM ist die virtuelle Maschine eine Software, die einen Interpreter, Klassenlader, Garbage Collector, Thread Scheduler, JIT-Compiler und viele andere Dinge enthält.

Wie Sie sehen können, ist der Interpreter ein Teil oder eine JVM, und die gesamte JVM kann nicht als Interpreter bezeichnet werden, da sie viele andere Komponenten enthält.

Warum sollte man das Wort "Interpreter" verwenden, wenn man über Python spricht?

Mit Java ist der Kompilierungsteil explizit. Python hingegen ist nicht explizit als Java über seinen Kompilierungs- und Interpretationsprozess, aus Sicht des Endbenutzers ist die Interpretation der einzige Mechanismus, der zum Ausführen von Python-Programmen verwendet wird


0

Nein, beide interpretieren den Bytecode nicht.

Python interpretiert Bytecode nur, wenn Sie mit pypy arbeiten. Andernfalls wird es in C kompiliert und auf dieser Ebene interpretiert.

Java wird zu Bytecode kompiliert.


Können Sie Ihrer Antwort Ressourcen geben?
Isuru Dilshan


Dies ist das Problem mit dem Stapelüberlauf. Jemand hat einen pissigen Anfall, weil er gerufen wird und ihn mit Abstimmungen ausdrückt.
Michael Tamillow

0

Ich denke, die Grenzen zwischen beiden sind verschwommen, die Leute streiten sich hauptsächlich um die Bedeutung des Wortes "Interpreter" und wie nahe die Sprache an jeder Seite des Spektrums "Interpreter ... Compiler" liegt. Keiner macht jedoch 100%. Ich denke, es ist einfach, eine Java- oder Python-Implementierung zu schreiben, die einen beliebigen Wert für das Spektrum hat.

Derzeit haben sowohl Java als auch Python virtuelle Maschinen und Bytecode, obwohl eine mit konkreten Wertgrößen (wie 32-Bit-Ganzzahlen) arbeitet, während die andere die Größe für jeden Aufruf bestimmen muss, was meiner Meinung nach nicht die Grenze zwischen den Begriffen definiert.

Das Argument, dass Python keinen offiziell definierten Bytecode hat und nur im Speicher vorhanden ist, überzeugt mich auch nicht, nur weil ich vorhabe, Geräte zu entwickeln, die nur Python-Bytecode erkennen und der Kompilierungsteil in einem Browser-JS-Computer ausgeführt wird.

Bei der Leistung geht es nur um die konkrete Umsetzung. Wir müssen die Größe des Objekts nicht kennen, um damit arbeiten zu können, und schließlich arbeiten wir in den meisten Fällen mit Strukturen, nicht mit Basistypen. Es ist möglich, Python VM so zu optimieren, dass jedes Mal während der Ausdrucksberechnung kein neues Objekt erstellt werden muss, indem vorhandenes wiederverwendet wird. Sobald dies erledigt ist, gibt es keinen globalen Leistungsunterschied zwischen der Berechnung der Summe zweier Ganzzahlen, wo Java glänzt.

Es gibt keinen entscheidenden Unterschied zwischen den beiden, nur einige Implementierungsnuancen und mangelnde Optimierung, die für den Endbenutzer irrelevant sind, möglicherweise bis zu dem Punkt, an dem sie Leistungsverzögerungen bemerkt, aber es handelt sich wiederum um ein Implementierungs- und nicht um ein Architekturproblem.


0

Bei Posts, in denen erwähnt wird, dass Python keinen Bytecode generieren muss, bin ich mir nicht sicher, ob dies der Fall ist. Es scheint, dass alle aufrufbaren Elemente in Python ein .__code__.co_codeAttribut haben müssen , das den Bytecode enthält. Ich sehe keinen sinnvollen Grund, Python als "nicht kompiliert" zu bezeichnen, nur weil die kompilierten Artefakte möglicherweise nicht gespeichert werden. und werden in Python häufig nicht vom Design gespeichert, z. B. kompilieren alle Verständnisse neuen Bytecode für die Eingabe. Dies ist der Grund, warum der Umfang der Verständlichkeitsvariablen zwischen compile(mode='exec, ...)und Kompilieren nicht konsistent ist , compile(mode='single', ...)z. B. zwischen dem Ausführen eines Python-Skripts und der Verwendung von pdb

Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.