it-swarm.com.de

Können wir allgemeine Aussagen über die Leistung von interpretiertem Code gegenüber kompiliertem Code machen?

Ich vergleiche zwei Technologien, um eine Empfehlung zu erhalten, für die eine von einem Unternehmen verwendet werden sollte. Der Code von Technologie A wird interpretiert, während der Code von Technologie B zu Maschinencode kompiliert wird. In meinem Vergleich stelle ich fest, dass Tech B im Allgemeinen eine bessere Leistung hätte, da es nicht den zusätzlichen Aufwand für den Interpretationsprozess hat. Ich stelle auch fest, dass es immer noch möglich ist, dass ein in Tech A geschriebenes Programm ein in Tech B geschriebenes Programm übertreffen kann, da ein Programm auf viele Arten geschrieben werden kann.

Als ich diesen Bericht zur Überprüfung einreichte, gab der Prüfer an, dass ich keinen klaren Grund angegeben habe, warum der Aufwand für den Interpretationsprozess im Allgemeinen groß genug wäre, um zu dem Schluss zu gelangen, dass die Leistung von Tech B besser wäre.

Meine Frage ist also, können wir jemals etwas über die Leistung kompilierter/interpretierter Technologien sagen? Wenn wir sagen können, dass kompiliert im Allgemeinen schneller ist als interpretiert, wie könnte ich den Rezensenten von meinem Standpunkt überzeugen?

60
EpicSam

Nein.

Im Allgemeinen hängt die Leistung einer Sprachimplementierung in erster Linie von der Menge an Geld, Ressourcen, Arbeitskräften, Forschung, Technik und Entwicklung ab, die dafür ausgegeben werden.

Insbesondere hängt die Leistung eines bestimmten Programms in erster Linie von der Menge an Gedanken ab, die in seine Algorithmen gesteckt werden.

Es gibt einige sehr schnelle Interpreter und einige Compiler, die sehr langsamen Code generieren.

Einer der Gründe, warum Forth immer noch beliebt ist, ist beispielsweise, dass ein interpretiertes Forth-Programm in vielen Fällen schneller ist als das entsprechende kompilierte C-Programm, während gleichzeitig das in Forth plus) geschriebene Benutzerprogramm verwendet wird der in C geschriebene Forth-Interpreter ist kleiner als das in C geschriebene Anwenderprogramm.

110
Jörg W Mittag

Verallgemeinerungen und spezifische Szenarien sind buchstäblich Gegensätze.

Sie scheinen sich selbst zu widersprechen. Einerseits möchten Sie eine allgemeine Aussage über interpretierte und kompilierte Sprachen machen. Andererseits möchten Sie diese allgemeine Aussage auf ein konkretes Szenario anwenden, das Technologie A und Technologie B umfasst.

Sobald Sie etwas auf ein konkretes Szenario anwenden , wird es nicht mehr verallgemeinert . Selbst wenn Sie behaupten können, dass interpretierte Sprachen im Allgemeinen langsamer sind , machen Sie immer noch keinen Standpunkt. Ihr Rezensent kümmert sich nicht um Verallgemeinerungen. Sie analysieren zwei sehr spezifische Technologien. Das ist buchstäblich das Gegenteil von Verallgemeinern.

81
loneboat

Als Faustregel gilt, dass ein interpretiertes Programm etwa 2x - 10x langsamer ist als das Schreiben des Programms in der Host-Sprache des Interpreters, wobei Dolmetscher für dynamischere Sprachen langsamer sind. Dies liegt daran, dass das interpretierte Programm die gesamte eigentliche Arbeit erledigen muss, aber zusätzlich den Interpretationsaufwand hat.

Abhängig von der Struktur des Dolmetschers kann es sehr signifikante Unterschiede geben. Es gibt zwei widersprüchliche Schulen für das Dolmetscherdesign: Eine sagt, Opcodes sollten so klein wie möglich sein, damit sie leichter optimiert werden können, die andere sagt, Opcodes sollten so groß wie möglich sein, damit wir mehr Arbeit innerhalb des Dolmetschers erledigen. Wenn die Struktur Ihres Programms der Philosophie des Dolmetschers entspricht, wird der Overhead vernachlässigbar.

Z.B. Perl ist eine interpretierte Sprache, die auf Textmanipulation ausgerichtet ist. Ein idiomatisches Perl-Programm, das Textmanipulationen durchführt, ist nicht viel langsamer als ein C-Programm und kann in einigen Fällen sogar das C-Programm übertreffen (möglich, da Perl eine andere Zeichenfolgendarstellung verwendet und verschiedene text- und E/A-bezogene Optimierungen integriert sind). Das Knacken von Zahlen in Perl wird jedoch unerträglich langsam sein. Ein Inkrement ++x ist eine einzelne Assembly-Anweisung, umfasst jedoch mehrere Zeigerdurchläufe und Verzweigungen für den Perl-Interpreter. Ich habe kürzlich ein CPU-gebundenes Perl-Skript nach C++ portiert und je nach Compiler-Optimierungsstufe eine 7- bis 20-fache Beschleunigung erhalten.

Hier ist es wichtig, über Optimierungen zu sprechen, da ein polierter, optimierter Interpreter einen nicht optimierenden naiven Compiler vernünftigerweise übertreffen kann. Da das Erstellen eines optimierenden Compilers schwierig ist und viel Aufwand erfordert, ist es unwahrscheinlich, dass Ihre „Technologie B“ diesen Reifegrad aufweist.

(Hinweis: Die Website Computer Language Benchmarks Game hat eine verwirrende Struktur, aber sobald Sie die Zeittabelle für ein Problem erreicht haben, werden Sie feststellen, dass die Leistung verschiedener Sprachen allgegenwärtig ist - häufig dort ist keine klare Leistungsgrenze zwischen kompilierten und interpretierten Lösungen. Der wichtigste Teil der Website sind nicht die Benchmark-Ergebnisse, sondern die Diskussionen darüber, wie schwierig aussagekräftige Benchmarks sind.)

Bei der Auswahl einer Technologie ist die Leistung einer Sprachlaufzeit an sich völlig irrelevant. Es ist wahrscheinlicher, dass die Technologie einige grundlegende Einschränkungen erfüllt (unser Budget beträgt $ x, wir müssen in der Lage sein, vor JJJJ-MM-TT zu liefern, wir müssen verschiedene nicht funktionale Anforderungen erfüllen) und dass es niedrigere Anforderungen gibt Gesamtbetriebskosten (unter Berücksichtigung der Entwicklerproduktivität, der Hardwarekosten, der Kosten für Geschäftsmöglichkeiten, des Risikos von Fehlern und unerwarteten technischen Einschränkungen, der Wartungskosten, der Schulungs- und Einstellungskosten usw.). Z.B. In einer Branche, in der die Markteinführungszeit der wichtigste Faktor ist, ist die Technologie mit der besten Entwicklerproduktivität am besten geeignet. Für ein großes Unternehmen sind Wartbarkeit und langfristige Kosten möglicherweise interessanter.

37
amon

Sie können absolut etwas über die Leistung kompilierter/interpretierter Technologien sagen. Aber zuerst müssen Sie "Leistung" definieren. Wenn Sie ein rechnerisch einfaches eingebettetes System erstellen, würde sich die "Leistung" wahrscheinlich eher auf die Seite der Speichernutzung konzentrieren. Während ein rechnerisch komplexes System, das mit großen Datenmengen arbeitet, die "Leistung" in der Anzahl der Berechnungen pro Zeiteinheit definieren würde, da der Speicheraufwand von JVM oder .NET vernachlässigbar wäre.

Sobald Sie sich für "Leistung" entschieden haben, können Sie so etwas wie "Wir haben zu jedem Zeitpunkt 50 Milliarden Objekte im Speicher" haben. Interpretierte techA fügt jedem Objekt zusätzliche 8 Bytes für die interne Verwaltung hinzu, was einem Speicheraufwand von 400 GB entspricht im Vergleich zu techB, das diese Daten nicht hinzufügt "

18
jhbh

Dies ist eine technische Frage, und Sie haben bereits viele gute technische Antworten erhalten, aber ich möchte auf einen etwas anderen Aspekt Ihrer Situation hinweisen: die Tatsache, dass Sie eine Entscheidung wie "Technologie A oder Technologie B" nicht einfach nur begründen können aus technischen und/oder Leistungsgründen.

Die technischen Aspekte von so etwas sind nur ein kleiner Teil der Entscheidung zwischen A und B. Es gibt Dutzende anderer Faktoren, die berücksichtigt werden müssen:

  • Enthält es Lizenzkosten? Zum Beispiel: Sie müssen (einen erheblichen Betrag) bezahlen, um einen Cluster von SQL Server-Computern zu verwenden, anstatt einen Cluster von PostgreSQL-Computern zu verwenden.
  • Habe ich Mitarbeiter, die mit dieser Technologie (Stack) und ihrem Ökosystem vertraut sind? Wenn ja, sind sie verfügbar? Wenn nein, kann ich welche mieten? Wie viel kostet es mich? Oder trainiere ich die vorhandenen? Wie viel kostet mich das?
  • was will der Kunde? Dies kann häufig ein Problem sein.
  • Ist die von mir empfohlene Technologie produktionsbereit? Oder ist es nur ein aktueller Hype, der möglicherweise aussterben wird? (Denken Sie beispielsweise an Node.js, als es herauskam)
  • Passt die von mir empfohlene Technologie gut zu der vorhandenen Architektur oder der Architektur, die ich mir vorgestellt habe? Oder muss ich viel Geld ausgeben, damit sie nahtlos zusammenarbeiten?
  • und viele weitere Aspekte, die von Ihrer spezifischen Situation abhängen.

Wie Sie sehen können, gibt es eine Menge Dinge zu beachten, wenn Sie eine solche Entscheidung treffen.

Ich weiß, dass dies Ihre Frage nicht speziell beantwortet, aber ich denke, es bietet einen umfassenderen Überblick über Ihre Situation und die Besonderheiten einer solchen Entscheidung.

12
Radu Murzea

Teilevaluierung ist ein konzeptioneller Rahmen, der relevant ist, um Interpreten und Compiler in Beziehung zu setzen.

Können wir allgemeine Aussagen über die Leistung von interpretiertem Code gegenüber kompiliertem Code machen?

Programmiersprachen sind Spezifikationen (in einigen Berichten geschrieben, z. B. R5RS oder n157 ). Sie sind keine Software, daher ist es nicht einmal sinnvoll, von Leistung zu sprechen. -). Einige Programmiersprachen können jedoch mehrere Implementierungen haben, einschließlich Interpreter und Compiler .

Selbst in traditionell kompilierten Sprachen (dh Sprachen, deren Implementierungen häufig Compiler sind) wie C werden einige Teile häufig interpretiert. Beispielsweise wird die Formatsteuerzeichenfolge von printf (im C-Standard definiert) häufig "interpretiert" (durch - C-Standardbibliothek , die eine printf Funktion unter Verwendung von Techniken mit variablen Argumenten hat), aber einige Compiler (einschließlich GCC ) können -in begrenzt spezielle Fälle - um es zu optimieren und in Aufrufe niedrigerer Ebene zu "kompilieren".

Und einige Implementierungen, sogar innerhalb von "Interpreten", verwenden JIT-Kompilierung Techniken (generieren Sie also Maschinencode zur Laufzeit ). Ein gutes Beispiel ist luajit . Andere Implementierungen (z. B. Python, Ocaml, Java, Parrot, Lua) übersetzen den Quellcode in einen Bytecode , der dann interpretiert wird.

SBCL ist ein Common LISP "Compiler", der jede REPL Interaktion (und ruft eval etc ...) in Maschinencode auf. Sie glauben also, es ist ein Dolmetscher. Die meisten JavaScript-Implementierungen in Browsern (z. B. v8 ) verwenden JIT-Kompilierungstechniken.

Mit anderen Worten, der Unterschied zwischen Interpreten und Compilern ist sehr unscharf (tatsächlich gibt es ein Kontinuum zwischen beiden), und praktisch gesehen haben die meisten Programmiersprachenimplementierungen häufig sowohl eine Interpreter- als auch eine Compiler-Facette (zumindest für Byte-Code).

Eine Implementierung kann schnell oder langsam sein, unabhängig davon, ob die meisten "Compiler" - oder "Interpreter" -ähnlichen Techniken verwendet werden.

Einige Sprachmerkmale bevorzugen einen Interpretationsansatz (und können nur durch Analyse des gesamten Programms effizient kompiliert werden).

Für einige Arten von Problemen lohnt sich das Entwerfen der Software mit einigen Metaprogrammierung Ansätzen und führt zu wichtigen Beschleunigungen. Sie können sich vorstellen, dass Ihr Programm bei einer bestimmten Eingabe dynamisch speziellen Code generiert, um ihn zu verarbeiten. Dies ist sogar möglich mit C oder C++ (entweder unter Verwendung einer JIT-Bibliothek oder durch Generieren von C-Code, der als Plugin kompiliert wird, das dynamisch geladen wird).

Siehe auch diese verwandte Frage zu Python und diese

10

Bei Code wie A = A + B Können bis zu ein oder zwei Maschinenbefehle kompiliert werden, die jeweils eine bestimmte Anzahl von Zyklen benötigen. Kein Dolmetscher kann aus einem einfachen Grund in dieser Anzahl von Zyklen dasselbe tun.

Der Interpreter führt auch einen eigenen Befehlssatz aus (nennen Sie sie Bytecodes, p-Codes, Zwischensprache, was auch immer). Jedes Mal, wenn ein Bytecode wie ADD angezeigt wird, muss er ihn irgendwie nachschlagen und zu dem Code verzweigen, der die Addition vornimmt.

Das nächste Mal, wenn es es sieht, muss es diese Suche wiederholen , es sei denn es hat eine Möglichkeit, sich an die vorherige Suche zu erinnern. Wenn es eine Möglichkeit gibt, sich an die vorherige Suche zu erinnern, ist es nicht mehr das, was wir als "Interpreter" bezeichnen, sondern ein Just-in-Time-Compiler oder JITter.

Auf der anderen Seite...

Wie viele Zyklen werden für Code wie callSomeFunction( ... some args ...) zwischen der Eingabe und dem Verlassen dieses Codes verbracht? Es hängt alles davon ab, was in callSomeFunction passiert. Es könnten ein paar sein, und es könnten Billionen sein, selbst wenn callSomeFunction selbst kompiliert ist. Wenn es viel ist, macht es keinen Sinn, über die Interpretationskosten dieser Codezeile zu debattieren - das Geld ist woanders.

Denken Sie daran, dass interpretierte Sprachen einen eigenen Wert haben, z. B. dass sie nicht kompiliert werden müssen. (Das "Kompilieren" der Oberflächensyntax zu Bytecodes nimmt nur wenig Zeit in Anspruch. Nehmen Sie zum Beispiel R oder MATLAB.)

Außerdem ist Flexibilität für intelligente Programmierebenen erforderlich. In Minskys Society of Mind , Kapitel 6.4 [~ # ~] b [~ # ~] - Gehirne, es gibt A-Programme, die sich mit der Welt befassen, und es gibt B-Programme, die sich mit A-Programmen befassen, und es kann weitere Ebenen geben. Programme, die andere Programme schreiben und verwalten, können in Interpretationssystemen einfacher ausgeführt werden.

In LISP können Sie (+ A B) Schreiben, um A und B hinzuzufügen, aber sobald es geschrieben ist, haben Sie nur die Wahl, es auszuführen oder nicht. Sie können auch (eval (list '+ 'A 'B)) Schreiben, das das Programm erstellt und dann ausführt. Es könnte etwas anderes konstruieren.

Das Thema des Programms ist ein anderes Programm . Dies ist einfacher in einer interpretierten Sprache zu schreiben (obwohl, wie Jörg betont, neuere Versionen von LISP, während sie eval haben, im laufenden Betrieb kompiliert werden können, haben sie nicht die Geschwindigkeitsstrafe des Dolmetschens ).

7
Mike Dunlavey

Ihre Annahme ist begründet, obwohl es sich um eine Annahme handelt.

Ich werde nicht auf die Gründe eingehen, warum kompilierter Code sollte schneller sein als interpretierter Code: Wenn Sie wissen, wie Computer funktionieren, ist das offensichtlich. Der Unterschied kann für bestimmte Problemtypen Größenordnungen betragen. Wenn Ihr Prüfer diesen allgemeinen Fall ernsthaft bestreitet, weiß er nicht, wovon er spricht.

Wo sie einen Punkt haben können, ist jedoch, ob der Unterschied in der Art der Anwendung, die Sie entwickeln, signifikant ist. Wenn es sich meistens um E/A handelt oder meistens kompilierte Bibliotheken aufruft und nicht viel Rechenaufwand vorhanden ist, kann der Aufwand für den Interpretationsprozess in der Tat unbedeutend sein.

Aber der Punkt meines Beitrags ist folgender: Als I.T. Als Experte werden Sie häufig aufgefordert, schnelle Entscheidungen zu treffen, die auf einem allgemeinen Wissen darüber beruhen, wie die Dinge funktionieren sollten. Wenn Sie einen bestimmten Test durchführen, erhalten Sie möglicherweise eine genauere Antwort, die jedoch viel mehr kostet und Sie nicht zuerst dorthin bringt.

Aber von Zeit zu Zeit werden Sie erwischt. Es ist mir passiert. Sie machen eine gute Annahme und stellen dann fest, dass Sie die Dummheit der Welt nicht berücksichtigt haben.

Aber ich kann es nicht so gut erklären wie meinen Lieblings-Dilbert-Cartoon aller Zeiten. Nichts zeigt besser als dies die Gefahren, ein kluger Arsch zu sein.

alt text

TL; DR: Sie sollten Recht haben, aber überprüfen Sie die reale Welt für alle Fälle.

5
rghome

Art, Art, es kommt darauf an, aber in der Regel ist die kompilierte Umgebung - sei es durch JIT oder statisch kompiliert - für viele rechenintensive Aufgaben schneller - vorausgesetzt, der Einfachheit halber wird dieselbe Sprache verwendet.

Ein Grund dafür ist, dass interpretierte Sprachen eine Interpreter-Schleife haben müssen, die eine Anweisung liest, die entsprechende Aktion auswählt und ausführt. Im besten Fall wie beim Interpretieren von Python oder Java Bytecode (wie alte JVM) ) Es hat einen Overhead von wenigen Anweisungen und hat mit dem Branch Predictor Chaos angerichtet - ohne den letzten können Sie aufgrund falscher Vorhersagen enorme Strafen erwarten. Selbst eine sehr dumme JIT sollte dies erheblich beschleunigen.

Das heißt, die interpretierte Sprache kann betrügen. Zum Beispiel hat Matlab Routinen für die Matrixmultiplikation optimiert und mit wenigen Änderungen kann Code auf der GPU ausgeführt werden (Haftungsausschluss: Ich arbeite für nVidia - jede hier geäußerte Meinung ist meine und repräsentiert nicht die Ansicht meines Arbeitgebers). Auf diese Weise können Sie kurzen und leistungsstarken Code auf höherer Ebene schreiben, ohne sich um Details kümmern zu müssen. Jemand hat sich darum gekümmert und Zeit und Ressourcen in die Optimierung in niedriger Sprache gesteckt. Es wird nichts geerbt und es verhindert beispielsweise nicht, dass Matlab den Code JIT-fähig macht, aber häufig gibt es keinen Grund, da der Aufwand für das Aufrufen von Routinen auf hoher Ebene im Vergleich zu der Zeit, die in Routinen auf niedriger Ebene verbracht wird, minimal ist.

TL; DR - Die kompilierten Programme haben gegenüber den interpretierten enorme Leistungsvorteile (zum Vergleich von Äpfeln zu Äpfeln siehe PyPy Speed ). Die Geschwindigkeit der ausführbaren Datei ist jedoch nur ein Teil des Problems und trägt möglicherweise nicht viel zur Gesamtgeschwindigkeit bei (wenn die Zeit hauptsächlich in Bibliotheken verbracht wird). Auch die Umsetzung ist wichtig.

5

Wenn Sie nicht etwas Exotisches verwenden, besteht Ihr Problem nicht in der Leistung einer interpretierten Sprache A und einer kompilierten Sprache B.

Denn wenn Sie/Ihr Team A und nicht B kennen und so viel besseren Code in A als B schreiben, können Sie in A eine viel bessere Leistung erzielen als in B. Wenn Sie Leute haben, die Erfahrung in einer Sprache haben und die Sprache/Bibliotheken dies können Job, den Sie brauchen, bleiben Sie dabei.

Hier ist ein Link zu Regex in verschiedenen Sprachen. Sie werden sehen, dass Regex in einigen Sprachen besser implementiert ist, selbst wenn es kompiliert wurde oder nicht: http://benchmarksgame.alioth.debian.org/u64q/performance.php?test=regexdna

3
Walfrat

Ich denke, es ist einfach keine gute Idee, über die Leistung zweier Technologien zu sprechen, nur weil eine kompiliert und die andere interpretiert wird. Wie in anderen Antworten angegeben, kann dies vom Anwendungsbereich (einige Sprachen können so optimiert werden, dass einige Vorgänge sehr schnell und andere langsamer ausgeführt werden) sowie von der Erfahrung von Personen abhängen, die diese Technologie verwenden möchten.

Ich denke nicht, dass es vernünftig ist zu erwarten, dass Sie einen Leistungsschub erhalten, wenn Sie einige hervorragend interpretierte Sprachcodierer nehmen und ihnen eine Technologie geben, mit der sie nicht vertraut sind - vielleicht kann letzteres theoretisch zu einer besseren Leistung führen, aber in Wirklichkeit. Ohne die erforderlichen Fähigkeiten und Erfahrungen werden Sie nicht alle Optimierungsmöglichkeiten nutzen.

Von einem der bekannten Mitarbeiter des Silicon Valley-Unternehmens habe ich auch gehört, dass sie die Sprache bevorzugen, die einfacher zu verwenden ist, da es teurer und mühsamer ist, einige erfahrene Entwickler für die Pflege eines komplizierten, aber hochoptimierten Codes zu bezahlen, als nur für Kaufen Sie mehr Rig, um mit der weniger effizienten Implementierung fertig zu werden, sodass dies auch bei der Auswahl der Technologie berücksichtigt werden sollte.

1
KjMag

Einmal musste ich eine ähnliche umfassende Erklärung abgeben, um eine große Entscheidung zu rechtfertigen.

Erstens möchten sie vielleicht einem bescheidenen Ingenieur nicht glauben, deshalb habe ich einige vergleichbare Benchmark-Tests gefunden und sie zitiert. Es gibt viele von ihnen, von Leuten wie Microsoft oder renommierten Universitäten. Und sie werden Dinge sagen wie: Methode A ist zwischen 3 und 10 Mal schneller als Methode B, abhängig von den Variablen X und Y.

Zweitens möchten Sie möglicherweise einen eigenen Benchmark ausführen, indem Sie möglicherweise einen repräsentativen Teil des betreffenden Codes oder etwas Ähnliches verwenden, das Sie bereits haben. Führen Sie es 1000 Mal über Nacht aus, damit es wirklich einen messbaren Unterschied gibt.

An diesem Punkt sollte der Unterschied (oder das Fehlen davon) zwischen A und B so klar sein, dass Sie ihn nur präsentieren müssen. Formatieren Sie die Ergebnisse daher klar und nach Möglichkeit mit Diagrammen, geben Sie alle Annahmen an und definieren Sie alle verwendeten Daten.

0
RedSonja

Ich würde argumentieren, dass jede dynamische Sprache einen Vorteil gegenüber statisch kompilierten hat: "Laufzeitoptimierungen"

Dies ist einer der Gründe Java kann schneller als C++ sein

Ja, Laden Eine dynamisch typisierte Sprache hat immer die Kosten für die Übersetzung und ist im Nachteil. Sobald es ausgeführt wird, kann der Interpreter häufige Codepfade mit Laufzeitinformationen profilieren und erweitern, die statische Sprachen niemals haben werden

HINWEIS: Nun, Java ist eine interpretierte Sprache, keine dynamische. Aber es ist ein großartiges Beispiel dafür, was Sie mit Laufzeitinformationen beschleunigen können

0
SystematicFrank