it-swarm.com.de

C ++ - Leistung im Vergleich zu Java / C #

Ich verstehe, dass C/C++ nativen Code erzeugt, der auf einer bestimmten Maschinenarchitektur ausgeführt werden kann. Umgekehrt werden Sprachen wie Java und C # auf einer virtuellen Maschine ausgeführt, die die native Architektur abstrahiert. Logischerweise scheint es unmöglich, dass Java oder C # übereinstimmt die Geschwindigkeit von C++ aufgrund dieses Zwischenschritts, jedoch wurde mir gesagt, dass die neuesten Compiler ("Hot Spot") diese Geschwindigkeit erreichen oder sogar übertreffen können.

Vielleicht ist dies eher eine Compiler-Frage als eine Sprachfrage, aber kann jemand im Klartext erklären, wie es möglich ist, dass eine dieser virtuellen Maschinensprachen eine bessere Leistung erbringt als eine Muttersprache?

119
user23126

Im Allgemeinen können C # und Java) genauso schnell oder schneller sein, weil der JIT-Compiler - ein Compiler, der Ihre IL bei der ersten Ausführung kompiliert - Optimierungen vornehmen kann, die ein C++ - kompiliertes Programm nicht kann Es kann den Computer abfragen und feststellen, ob es sich um einen Intel- oder AMD-Computer, Pentium 4, Core Solo oder Core Duo-Computer handelt oder ob SSE4 usw. unterstützt wird.

Ein C++ - Programm muss im Voraus in der Regel mit gemischten Optimierungen kompiliert werden, damit es auf allen Computern einwandfrei funktioniert, jedoch nicht so optimiert ist, wie es für eine einzelne Konfiguration (d. H. Prozessor, Befehlssatz, andere Hardware) möglich wäre.

Zusätzlich erlauben es bestimmte Sprachfunktionen dem Compiler in C # und Java), Annahmen über Ihren Code zu treffen, die es ihm ermöglichen, bestimmte Teile zu optimieren, die für den C/C++ - Compiler einfach nicht sicher sind Sie haben Zugriff auf Zeiger. Es gibt viele Optimierungen, die einfach nicht sicher sind.

Auch Java und C # können Heap-Zuweisungen effizienter ausführen als C++, da die Abstraktionsschicht zwischen dem Garbage Collector und Ihrem Code es ihm ermöglicht, die gesamte Heap-Komprimierung auf einmal durchzuführen (eine ziemlich teure Operation). .

Jetzt kann ich nicht für Java zu diesem nächsten Punkt sprechen, aber ich weiß, dass C # zum Beispiel tatsächlich Methoden und Methodenaufrufe entfernt, wenn es weiß, dass der Hauptteil der Methode leer ist. Und das wird es Verwenden Sie diese Art von Logik im gesamten Code.

Wie Sie sehen, gibt es viele Gründe, warum bestimmte C # - oder Java - Implementierungen schneller sind.

Nun können in C++ bestimmte Optimierungen vorgenommen werden, die alles in die Luft jagen, was Sie mit C # tun können, insbesondere im Grafikbereich und immer dann, wenn Sie in der Nähe der Hardware sind. Zeiger wirken hier Wunder.

Also, je nachdem, was Sie schreiben, würde ich mit dem einen oder anderen gehen. Aber wenn Sie etwas schreiben, das nicht hardwareabhängig ist (Treiber, Videospiel usw.), würde ich mir keine Sorgen um die Leistung von C # machen (ich kann wieder nicht über Java sprechen). Es wird gut gehen.

Einer der Java Seite, @ Swati weist auf einen guten Artikel hin:

https://www.ibm.com/developerworks/library/j-jtp09275

179
Orion Adrian

JIT vs. Static Compiler

Wie bereits in den vorherigen Beiträgen erwähnt, kann JIT IL/Bytecode zur Laufzeit in systemeigenen Code kompilieren. Die Kosten dafür wurden erwähnt, aber nicht zu seinem Schluss:

Ein großes Problem bei JIT ist, dass es nicht alles kompilieren kann: Das Kompilieren von JIT nimmt Zeit in Anspruch, daher kompiliert JIT nur einige Teile des Codes, während ein statischer Compiler eine vollständige native Binärdatei erzeugt: Bei manchen Programmen ist es die statische Der Compiler wird die JIT einfach übertreffen.

Natürlich ist C # (oder Java oder VB) in der Regel schneller zu einer brauchbaren und robusten Lösung als C++ (wenn auch nur, weil C++ eine komplexe Semantik hat und die C++ - Standardbibliothek zwar interessant und leistungsfähig, aber im Vergleich zur vollständigen Bibliothek ziemlich schlecht ist Umfang der Standardbibliothek von .NET oder Java), daher ist der Unterschied zwischen C++ und .NET oder Java JIT für die meisten Benutzer und für diejenigen Binärdateien, die kritisch sind, normalerweise nicht sichtbar Nun, Sie können die C++ - Verarbeitung immer noch über C # oder Java (selbst wenn diese Art von nativen Aufrufen für sich genommen recht kostspielig sein kann) aufrufen ...

C++ - Metaprogrammierung

Beachten Sie, dass Sie normalerweise C++ - Laufzeitcode mit dem entsprechenden Code in C # oder Java vergleichen. Aber C++ hat eine Funktion, die Java/C # von Anfang an übertreffen kann, nämlich die Template-Metaprogrammierung: Die Code-Verarbeitung wird zur Kompilierungszeit ausgeführt (was die Kompilierungszeit erheblich verlängert), was zu einer Laufzeit von null (oder fast null) führt.

Ich habe noch so einen realen Effekt auf dieses gesehen (ich spielte nur mit Konzepten, aber bis dahin war der Unterschied Sekunden der Ausführung für JIT, und null für C++), aber das ist erwähnenswert, neben der Tatsache, dass Template-Metaprogrammierung nicht trivial ist ...

Edit 2011-06-10: In C++ wird das Spielen mit Typen zur Kompilierungszeit ausgeführt. Dies bedeutet, dass generischer Code generiert wird, der nicht generischen Code aufruft (z. B. ein generischer Parser von String zu Typ T, der Standardbibliotheks-API für erkannte Typen T aufruft und den Parser auf einfache Weise durch erweiterbar macht Deren Benutzer) ist sehr einfach und sehr effizient, wohingegen das Entsprechende in Java oder C # bestenfalls schmerzhaft zu schreiben ist und zur Laufzeit immer langsamer und aufgelöst wird, selbst wenn die Typen beim Kompilieren bekannt sind Zeit, was bedeutet, Ihr nur Hoffnung ist für die JIT, um die ganze Sache inline.

...

Bearbeiten 20.09.2011: Das Team hinter Blitz ++ ( Homepage , Wikipedia ) ist diesen Weg gegangen, und anscheinend ist es ihr Ziel, FORTRANs Leistung bei wissenschaftlichen Berechnungen zu erreichen, indem es so viel wie möglich von der Laufzeitausführung auf eins verlagert Kompilierungszeit, über C++ - Template-Metaprogrammierung. Also die "Ich habe noch so einen echten Lebenseffekt gesehen"Teil, den ich oben anscheinend schrieb tut existieren im wirklichen Leben.

Native C++ - Speichernutzung

C++ hat eine andere Speichernutzung als Java/C # und daher andere Vorteile/Fehler.

Unabhängig von der JIT-Optimierung wird nichts schneller als ein direkter Zeigerzugriff auf den Speicher (lassen Sie uns einen Moment lang die Prozessor-Caches ignorieren usw.). Wenn Sie also zusammenhängende Daten im Speicher haben, geht der Zugriff über C++ - Zeiger (d. H. C-Zeiger ... Lassen Sie uns Caesar die Fälligkeit geben) schneller als in Java/C #. Und C++ hat RAII, was die Verarbeitung erheblich vereinfacht als in C # oder sogar in Java. C++ benötigt using nicht, um die Existenz seiner Objekte zu erfassen. Und C++ hat keine finally -Klausel. Dies ist kein Fehler.

:-)

Und trotz C # -primitiv-artiger Strukturen kosten C++ "auf dem Stapel" -Objekte bei Zuweisung und Zerstörung nichts und benötigen keine GC, um in einem unabhängigen Thread zu arbeiten, um die Bereinigung durchzuführen.

Was die Speicherfragmentierung betrifft, so sind die Speicherzuordnungen im Jahr 2008 nicht die alten Speicherzuordnungen aus dem Jahr 1980, die normalerweise mit einer GC: C++ - Zuordnung verglichen werden. Sie können zwar nicht in den Arbeitsspeicher verschoben werden, aber dann wie auf einem Linux-Dateisystem: Wer braucht eine Festplatte? Defragmentierung, wenn keine Fragmentierung stattfindet? Die Verwendung des richtigen Zuweisers für die richtige Aufgabe sollte Teil des C++ - Entwickler-Toolkits sein. Jetzt ist es nicht einfach, Allokatoren zu schreiben, und dann haben die meisten von uns bessere Dinge zu tun, und für die meisten Anwendungen ist RAII oder GC mehr als gut genug.

Bearbeiten Sie 2011-10-04: Beispiele für effiziente Allokatoren: Auf Windows-Plattformen ist seit Vista standardmäßig Low Fragmentation Heap aktiviert. In früheren Versionen kann der LFH durch Aufrufen der WinAPI-Funktion HeapSetInformation ) aktiviert werden. Auf anderen Betriebssystemen werden alternative Zuweiser bereitgestellt (siehe https://secure.wikimedia.org/wikipedia/en/wiki/Malloc für eine Liste)

Jetzt wird das Speichermodell mit dem Aufkommen der Multicore- und Multithreading-Technologie etwas komplizierter. In diesem Bereich hat .NET wohl den Vorteil, und Java, so wurde mir gesagt, hat die Oberhand gewonnen. Es ist leicht für einen "auf dem Holz" -Hacker, seinen "Near the Machine" -Code zu loben. Aber jetzt ist es viel schwieriger, eine bessere Assembly von Hand zu erstellen, als den Compiler an seine Arbeit zu übergeben. Für C++ wurde der Compiler seit einem Jahrzehnt in der Regel besser als der Hacker. Für C # und Java ist dies noch einfacher.

Dennoch wird der neue Standard C++ 0x C++ - Compilern ein einfaches Speichermodell auferlegen, das effektiven Multiprozessor-/Parallel-/Threading-Code in C++ standardisiert (und damit vereinfacht) und Optimierungen für Compiler einfacher und sicherer macht. Aber dann werden wir in ein paar Jahren sehen, ob seine Versprechen wahr sind.

C++/CLI vs. C #/VB.NET

Hinweis: In diesem Abschnitt spreche ich von C++/CLI, d. H. Dem von .NET gehosteten C++, nicht dem nativen C++.

Letzte Woche hatte ich eine Schulung zur .NET-Optimierung und stellte fest, dass der statische Compiler sowieso sehr wichtig ist. So wichtig wie JIT.

Derselbe Code, der in C++/CLI kompiliert wurde (oder dessen Vorgänger Managed C++), ist möglicherweise um ein Vielfaches schneller als derselbe Code, der in C # (oder VB.NET, dessen Compiler dieselbe IL erzeugt wie C #) erstellt wurde.

Weil der statische C++ - Compiler bereits optimierten Code viel besser produzieren konnte als C #.

Beispielsweise ist das Inlining von Funktionen in .NET auf Funktionen beschränkt, deren Bytecode höchstens 32 Byte lang ist. Aus diesem Grund erzeugt ein Teil des C # -Codes einen 40-Byte-Accessor, der vom JIT nicht mehr unterstützt wird. Derselbe Code in C++/CLI erzeugt einen 20-Byte-Accessor, der von der JIT eingefügt wird.

Ein weiteres Beispiel sind temporäre Variablen, die vom C++ - Compiler einfach kompiliert werden, während sie in der vom C # -Compiler erstellten IL noch erwähnt werden. Die Optimierung der statischen C++ - Kompilierung führt zu weniger Code und ermöglicht somit erneut eine aggressivere JIT-Optimierung.

Der Grund dafür wurde vermutet, dass der C++/CLI-Compiler von den umfangreichen Optimierungstechniken des nativen C++ - Compilers profitierte.

Fazit

Ich liebe C++.

Aus meiner Sicht sind C # oder Java) insgesamt eine bessere Wahl. Nicht, weil sie schneller als C++ sind, sondern weil sie, wenn man ihre Qualitäten addiert, am Ende mehr sind Produktiv, weniger Schulungsaufwand und umfassendere Standardbibliotheken als C++. Und wie bei den meisten Programmen sind die Geschwindigkeitsunterschiede (auf die eine oder andere Weise) vernachlässigbar ...

Bearbeiten (06.06.2011)

Meine Erfahrung auf C # /. NET

Ich habe jetzt 5 Monate lang fast ausschließliches professionelles C # -Codieren (was zu meinem bereits mit C++ und Java gefüllten Lebenslauf und einem Hauch von C++/CLI addiert).

Ich habe mit WinForms (Ahem ...) und WCF (cool!) Und WPF (cool !!!! Sowohl über XAML als auch über Raw-C # gespielt. WPF ist meiner Meinung nach so einfach, dass Swing einfach nicht damit zu vergleichen ist) und C # 4.0.

Die Schlussfolgerung ist, dass es zwar einfacher/schneller ist, einen Code zu erstellen, der in C #/Java funktioniert als in C++, es jedoch viel schwieriger ist, einen starken, sicheren und robusten Code in C # zu erstellen (und noch schwieriger in Java) als in C++. Gründe gibt es zuhauf, aber es kann zusammengefasst werden durch:

  1. Generika sind nicht so leistungsfähig wie Vorlagen (versuchen Sie, eine effiziente generische Parse-Methode (von String zu T) oder ein effizientes Äquivalent von boost :: lexical_cast in C # zu schreiben, um das Problem zu verstehen)
  2. RAII bleibt unerreicht (GC kann immer noch auslaufen (ja, ich musste dieses Problem behandeln) und wird nur den Speicher behandeln. Sogar C # 's using ist nicht so einfach und leistungsstark, da das Schreiben einer korrekten Dispose-Implementierung schwierig ist)
  3. C # readonly und Java final sind nirgends so nützlich wie C++ 'const (Es gibt keine Möglichkeit, in C # schreibgeschützte komplexe Daten (z. B. einen Baum von Knoten) ohne viel Arbeit verfügbar zu machen, während dies eine integrierte Funktion von C++ ist. Unveränderliche Daten sind eine interessante Lösung, aber nicht alles kann unveränderlich gemacht werden, so dass es bei weitem nicht einmal genug ist).

So bleibt C # eine angenehme Sprache, solange Sie etwas möchten, das funktioniert, aber eine frustrierende Sprache, sobald Sie etwas möchten, das funktioniert immer und sicher funktioniert.

Java ist sogar noch frustrierender, da es dieselben Probleme wie C # hat und noch viel mehr: Da es das Äquivalent des using - Schlüsselworts von C # nicht gibt, hat ein sehr erfahrener Kollege zu viel Zeit damit verbracht, sicherzustellen, dass seine Ressourcen ordnungsgemäß freigegeben wurden Das Äquivalent in C++ wäre einfach gewesen (mit Destruktoren und intelligenten Zeigern).

Ich denke also, dass der Produktivitätsgewinn von C #/Java für die meisten Codes sichtbar ist ... bis zu dem Tag, an dem der Code so perfekt wie möglich sein muss. An diesem Tag wirst du Schmerzen kennen. (Sie werden nicht glauben, was von unseren Server- und GUI-Apps verlangt wird ...).

Über Server-Seite Java und C++

Ich blieb mit den Serverteams auf der anderen Seite des Gebäudes in Kontakt (ich habe zwei Jahre unter ihnen gearbeitet, bevor ich wieder zum GUI-Team zurückgekehrt bin) und habe etwas Interessantes gelernt.

In den letzten Jahren ging der Trend dahin, dass die Java Server-Apps die alten C++ Server-Apps ersetzen sollten, da Java viele Frameworks/Tools hat, und ist einfach zu warten, bereitzustellen, etc. etc ..

... bis das Problem der geringen Latenz in den letzten Monaten seinen hässlichen Kopf aufrichtete. Dann haben die Java Server-Apps, unabhängig von den Optimierungsversuchen unseres erfahrenen Java -Teams, das Rennen gegen das alte, nicht wirklich optimierte C++ einfach und sauber verloren Server.

Derzeit besteht die Entscheidung darin, die Java - Server für den allgemeinen Gebrauch beizubehalten, wenn die Leistung noch wichtig ist, das Ziel mit geringer Latenz keine Rolle spielt, und die ohnehin schnelleren C++ - Serveranwendungen aggressiv für Anwendungen mit geringer Latenz zu optimieren. Latenz und extrem niedrige Latenzanforderungen.

Fazit

Nichts ist so einfach wie erwartet.

Java und noch mehr C # sind coole Sprachen mit umfangreichen Standardbibliotheken und Frameworks, in denen Sie schnell programmieren können und das Ergebnis sehr bald vorliegen wird.

Aber wenn Sie rohe Leistung, leistungsstarke und systematische Optimierungen, starke Compilerunterstützung, leistungsstarke Sprachfunktionen und absolute Sicherheit benötigen, machen es Java und C # schwierig, die letzten fehlenden, aber kritischen Qualitätsprozente zu gewinnen, die Sie benötigen über der Konkurrenz bleiben.

Es ist, als ob Sie in C #/Java weniger Zeit und weniger erfahrene Entwickler benötigen als in C++, um Code mit durchschnittlicher Qualität zu erstellen. In dem Moment, in dem Sie einen exzellenten bis perfekten Code benötigen, war es jedoch plötzlich einfacher und schneller, die Ergebnisse zu erzielen direkt in C++.

Natürlich ist dies meine eigene Wahrnehmung, vielleicht beschränkt auf unsere spezifischen Bedürfnisse.

Dennoch ist es das, was heute passiert, sowohl in den GUI-Teams als auch in den serverseitigen Teams.

Natürlich aktualisiere ich diesen Beitrag, wenn etwas Neues passiert.

Bearbeiten (2011-06-22)

"Wir stellen fest, dass C++ in Bezug auf die Leistung mit großem Vorsprung gewinnt. Es waren jedoch auch die umfangreichsten Optimierungsanstrengungen erforderlich, von denen viele auf einem Niveau durchgeführt wurden, das einem durchschnittlichen Programmierer nicht zur Verfügung stehen würde.

[...] Die Java) - Version war wahrscheinlich die am einfachsten zu implementierende, aber am schwierigsten zu analysierende Version. Insbesondere die Auswirkungen auf die Garbage Collection waren kompliziert und nur schwer abzustimmen. "

Quellen:

Bearbeiten (20.09.2011)

"Das entscheidende Wort bei Facebook ist, dassvernünftig geschriebener C++ - Code läuft einfach schnell,'was den enormen Aufwand für die Optimierung von PHP und Java) - Code unterstreicht. Paradoxerweise ist C++ - Code schwieriger zu schreiben als in anderen Sprachen, aber effizienter Code ist viel einfacher [in C++ zu schreiben als in anderen Sprachen]."

- Herb Sutter um // build / , zitierend Andrei Alexandresc

Quellen:

197
paercebal

Immer wenn ich über verwaltete oder nicht verwaltete Leistung spreche, möchte ich auf die Serie verweisen, in der Rico (und Raymond) C++ - und C # -Versionen eines Chinesisch/Englisch-Wörterbuchs verglichen haben. Mit diesem Google-Suche können Sie selbst lesen, aber ich mag Ricos Zusammenfassung.

Schäme ich mich also für meine vernichtende Niederlage? Kaum. Der gemanagte Code brachte für kaum einen Aufwand ein sehr gutes Ergebnis. Um den verwalteten Raymond zu besiegen, musste er:

  • Schreiben Sie seine eigenen I/O-Dateien
  • Schreiben Sie eine eigene Stringklasse
  • Schreiben Sie seinen eigenen Allokator
  • Schreiben Sie sein eigenes internationales Mapping

Natürlich benutzte er dafür verfügbare Bibliotheken niedrigerer Ebenen, aber das ist immer noch viel Arbeit. Können Sie aufrufen, was ein STL-Programm übrig hat? Ich glaube nicht, ich glaube, er hat die std :: vector Klasse beibehalten, was letztendlich nie ein Problem war, und er hat die Suchfunktion beibehalten. So ziemlich alles andere ist weg.

Sie können die CLR also definitiv übertreffen. Raymond kann sein Programm noch schneller machen, denke ich.

Interessanterweise ist die Zeit zum Parsen der Datei, wie von den internen Timern beider Programme gemeldet, ungefähr gleich - jeweils 30 ms. Der Unterschied liegt im Overhead.

Für mich bedeutet dies, dass die nicht verwaltete Version 6 Revisionen benötigte, um die verwaltete Version zu übertreffen, die ein einfacher Port des ursprünglichen nicht verwalteten Codes war. Wenn Sie jede Menge Leistung benötigen (und die Zeit und das Fachwissen haben, um diese zu erhalten), müssen Sie nicht verwaltet werden, aber für mich nehme ich den Vorteil in der Größenordnung, den ich bei den ersten Versionen gegenüber den 33 habe % Ich gewinne, wenn ich es 6 Mal versuche.

48
Jon Norton

Die Kompilierung für bestimmte CPU-Optimierungen wird normalerweise überbewertet. Nehmen Sie einfach ein Programm in C++ und kompilieren Sie es mit der Optimierung für Pentium PRO und führen Sie es auf einem Pentium 4 aus. Dann kompilieren Sie es erneut mit der Optimierung für Pentium 4. Ich habe lange Nachmittage damit verbracht, es mit mehreren Programmen zu tun. Allgemeine Ergebnisse? Normalerweise weniger als 2-3% Leistungssteigerung. Die theoretischen JIT-Vorteile sind also so gut wie keine. Die meisten Leistungsunterschiede lassen sich nur bei Verwendung skalarer Datenverarbeitungsfunktionen feststellen, für die möglicherweise eine manuelle Feinabstimmung erforderlich ist, um dennoch eine maximale Leistung zu erzielen. Optimierungen dieser Art sind langsam und kostenintensiv, so dass sie manchmal ohnehin nicht für JIT geeignet sind.

In der realen Welt und in realen Anwendungen ist C++ in der Regel immer noch schneller als Java, hauptsächlich aufgrund des geringeren Speicherbedarfs, der zu einer besseren Cache-Leistung führt.

Um jedoch alle C++ - Funktionen nutzen zu können, muss der Entwickler hart arbeiten. Sie können überlegene Ergebnisse erzielen, aber Sie müssen Ihr Gehirn dafür verwenden. C++ ist eine Sprache, die sich entschlossen hat, Ihnen mehr Tools anzubieten, und den Preis berechnet, den Sie für das Erlernen dieser Tools verlangen, um die Sprache gut verwenden zu können.

27
OldMan

JIT (Just In Time Compiling) kann unglaublich schnell sein, da es für die Zielplattform optimiert ist.

Dies bedeutet, dass jeder Compiler-Trick, den Ihre CPU unterstützt, ausgenutzt werden kann, unabhängig davon, auf welcher CPU der Entwickler den Code geschrieben hat.

Das Grundkonzept des .NET JIT sieht folgendermaßen aus (stark vereinfacht):

Erstmaliges Aufrufen einer Methode:

  • Ihr Programmcode ruft eine Methode Foo () auf
  • Die CLR untersucht den Typ, der Foo () implementiert, und ruft die zugehörigen Metadaten ab
  • Aus den Metadaten weiß die CLR, in welcher Speicheradresse der IL (Intermediate Byte Code) gespeichert ist.
  • Die CLR weist einen Speicherblock zu und ruft die JIT auf.
  • Die JIT kompiliert die IL in systemeigenen Code, platziert sie im zugewiesenen Speicher und ändert dann den Funktionszeiger in den Typmetadaten von Foo () so, dass er auf diesen systemeigenen Code verweist.
  • Der native Code wird ausgeführt.

Eine Methode zum zweiten Mal aufrufen:

  • Ihr Programmcode ruft eine Methode Foo () auf
  • Die CLR untersucht den Typ, der Foo () implementiert, und findet den Funktionszeiger in den Metadaten.
  • Der native Code an diesem Speicherort wird ausgeführt.

Wie Sie sehen, ist dies beim zweiten Mal praktisch derselbe Vorgang wie in C++, nur mit dem Vorteil von Echtzeitoptimierungen.

Das heißt, es gibt noch andere Overhead-Probleme, die eine verwaltete Sprache verlangsamen, aber das JIT hilft sehr.

21
FlySwat

Ich mag die Antwort von Orion Adrian , aber es gibt noch einen anderen Aspekt.

Dieselbe Frage wurde vor Jahrzehnten bezüglich der Assemblersprache im Vergleich zu "menschlichen" Sprachen wie FORTRAN gestellt. Ein Teil der Antwort ist ähnlich.

Ja, ein C++ - Programm kann auf einem beliebigen (nicht trivialen?) Algorithmus schneller als C # sein, aber das Programm in C # ist häufig genauso schnell oder schneller als eine "naive" Implementierung in C++ und eine optimierte Version in C++ Die Entwicklung wird länger dauern und könnte die C # -Version noch um einen kleinen Vorsprung übertreffen. Also, ist es das wirklich wert?

Sie müssen diese Frage einzeln beantworten.

Trotzdem bin ich ein langjähriger Fan von C++ und ich denke, es ist eine unglaublich ausdrucksstarke und mächtige Sprache - manchmal unterschätzt. Aber in vielen "echten" Problemen (für mich persönlich bedeutet das "die Art, für die ich bezahlt werde") wird C # die Arbeit schneller und sicherer erledigen.

Die größte Strafe, die Sie bezahlen? Viele .NET und Java Programme sind Speicherfresser. Ich habe gesehen, dass .NET und Java Apps "Hunderte" von Megabyte Speicher benötigen, wenn C++ - Programme ähnlich sind Komplexität kratzt kaum die "Zehner" von MBs.

12
Euro Micelli

Ich bin mir nicht sicher, wie oft Sie feststellen werden, dass Java Code auch mit Hotspot schneller als C++ ausgeführt wird, aber ich werde ein wenig darüber nachdenken, wie das passieren kann.

Stellen Sie sich kompilierten Java Code als interpretierte Maschinensprache für die JVM vor. Wenn der Hotspot-Prozessor feststellt, dass bestimmte Teile des kompilierten Codes häufig verwendet werden, führt er eine Optimierung des Maschinencodes durch Da die Handoptimierung von Assembly fast immer schneller ist als der von C++ kompilierte Code, ist es in Ordnung, dass programmgesteuert optimierter Maschinencode nicht z schlecht sein wird.

Für sich sehr wiederholenden Code konnte ich also sehen, wo es für Hotspot JVM möglich sein würde, Java schneller als C++ ... auszuführen, bis die Garbage Collection ins Spiel kommt. :)

7
billjamesdev

Im Allgemeinen ist Algorithmus Ihres Programms für die Geschwindigkeit Ihrer Anwendung viel wichtiger als Sprache. Sie können einen schlechten Algorithmus in jeder Sprache implementieren, einschließlich C++. Vor diesem Hintergrund können Sie in der Regel Code schreiben, der in einer Sprache ausgeführt wird, mit der Sie einen effizienteren Algorithmus implementieren können.

Sprachen auf höherer Ebene machen dies sehr gut, indem sie den Zugriff auf viele effiziente vorgefertigte Datenstrukturen vereinfachen und Methoden fördern, mit denen Sie ineffizienten Code vermeiden können. Natürlich können sie es manchmal auch einfach machen, ein paar wirklich langsame Codes zu schreiben, sodass Sie Ihre Plattform immer noch kennen müssen.

Außerdem holt C++ die "neuen" Funktionen (beachten Sie die Anführungszeichen) wie die STL-Container, Auto-Zeiger usw. ein - siehe zum Beispiel die Boost-Bibliothek. Und Sie werden gelegentlich feststellen, dass der schnellste Weg, eine Aufgabe zu erledigen, eine Technik wie Zeigerarithmetik erfordert, die in einer höheren Sprache verboten ist - obwohl Sie damit in der Regel eine Bibliothek aufrufen können, die in einer Sprache geschrieben ist, die sie wie gewünscht implementieren kann .

Die Hauptsache ist, die Sprache, die Sie verwenden, die zugehörige API, die Möglichkeiten und die Einschränkungen zu kennen.

6
Joel Coehoorn

Ich weiß es auch nicht ... meine Java Programme sind immer langsam. :-) Ich habe jedoch nie wirklich bemerkt, dass C # -Programme besonders langsam sind.

5
Paul Nathan

Sie sollten "Leistung besser als ..." definieren. Nun, ich weiß, Sie haben nach der Geschwindigkeit gefragt, aber es ist nicht alles, was zählt.

  • Führen virtuelle Maschinen einen höheren Laufzeitaufwand durch? Ja!
  • Essen sie mehr Arbeitsgedächtnis? Ja!
  • Haben sie höhere Startkosten (Laufzeitinitialisierung und JIT-Compiler)? Ja!
  • Benötigen sie eine riesige Bibliothek? Ja!

Und so weiter, es ist voreingenommen, ja;)

Mit C # und Java) zahlen Sie einen Preis für das, was Sie erhalten (schnelleres Codieren, automatische Speicherverwaltung, große Bibliothek usw.) Komplettpaket oder nichts.

Selbst wenn diese Sprachen einen Code so optimieren können, dass er schneller ausgeführt wird als kompilierter Code, ist der gesamte Ansatz (IMHO) ineffizient. Stellen Sie sich vor, Sie fahren jeden Tag 5 Meilen mit einem LKW zu Ihrem Arbeitsplatz! Es ist bequem, es fühlt sich gut an, Sie sind in Sicherheit (extreme Knautschzone) und nachdem Sie einige Zeit Gas gegeben haben, ist es sogar so schnell wie ein Standardauto! Warum haben wir nicht alle einen Lastwagen, um zur Arbeit zu fahren? ;)

In C++ bekommen Sie, wofür Sie bezahlen, nicht mehr und nicht weniger.

Zitat von Bjarne Stroustrup: "C++ ist meine Lieblingssprache, weil es so wenig Müll erzeugt" Linktext

4
Frunsi

Hier ist ein weiterer interessanter Benchmark, den Sie selbst auf Ihrem eigenen Computer testen können.

Es vergleicht ASM, VC++, C #, Silverlight, Java Applet, Javascript, Flash (AS3))

Roozz Plugin Speed ​​Demo

Bitte beachten Sie, dass die Geschwindigkeit von Javascript stark von dem Browser abhängt, der es ausführt. Dasselbe gilt für Flash und Silverlight, da diese Plugins im selben Prozess wie der Hosting-Browser ausgeführt werden. Das Roozz-Plugin führt jedoch Standard-EXE-Dateien aus, die in einem eigenen Prozess ausgeführt werden, sodass die Geschwindigkeit nicht vom Hosting-Browser beeinflusst wird.

4
Thomas

Hier einige gute Antworten zu der spezifischen Frage, die Sie gestellt haben. Ich würde gerne einen Schritt zurücktreten und das Gesamtbild betrachten.

Denken Sie daran, dass die Wahrnehmung des Benutzers für die Geschwindigkeit der von Ihnen geschriebenen Software von vielen anderen Faktoren beeinflusst wird, als nur davon, wie gut der Codegen optimiert ist. Hier sind einige Beispiele:

  • Die manuelle Speicherverwaltung ist schwierig (keine Lecks) und noch schwieriger (freier Speicher kurz nachdem Sie damit fertig sind). Die Verwendung eines GC führt im Allgemeinen eher zu einem Programm, das den Speicher gut verwaltet. Sind Sie bereit, sehr hart zu arbeiten und die Lieferung Ihrer Software zu verzögern, um den GC zu übertreffen?

  • Mein C # ist leichter zu lesen und zu verstehen als mein C++. Ich habe auch mehr Möglichkeiten, mich davon zu überzeugen, dass mein C # -Code ordnungsgemäß funktioniert. Das bedeutet, dass ich meine Algorithmen mit einem geringeren Fehlerrisiko optimieren kann (und Benutzer mögen keine Software, die abstürzt, auch wenn es schnell geht!)

  • Ich kann meine Software in C # schneller erstellen als in C++. Das spart Zeit, um an der Leistung zu arbeiten und meine Software trotzdem pünktlich zu liefern.

  • Es ist einfacher, eine gute Benutzeroberfläche in C # als in C++ zu schreiben, sodass ich eher in der Lage bin, die Arbeit in den Hintergrund zu schieben, während die Benutzeroberfläche reagiert, oder eine Fortschritts- oder Hörproben-Benutzeroberfläche bereitzustellen, wenn das Programm eine Weile blockieren muss. Das macht zwar nichts schneller, aber die Benutzer freuen sich über das Warten.

Alles, was ich über C # gesagt habe, trifft wahrscheinlich auf Java zu. Ich habe einfach nicht die Erfahrung, um es mit Sicherheit zu sagen.

3
Jay Bazuzi

Orion Adrian , lass mich deinen Beitrag umkehren, um zu sehen, wie unbegründet deine Bemerkungen sind, denn auch über C++ kann man viel sagen. Und zu sagen, dass der Java/C # -Compiler leere Funktionen wegoptimiert, lässt Sie wirklich so klingen, als wären Sie nicht mein Experte für Optimierung, denn a) warum sollte ein echtes Programm leere Funktionen enthalten, mit Ausnahme von wirklich schlechten Legacy-Code, b) das ist wirklich nicht schwarz und Bleeding Edge-Optimierung.

Abgesehen von diesem Satz haben Sie sich offen über Zeiger geärgert, aber funktionieren Objekte in Java und C # im Grunde genommen nicht wie C++ - Zeiger? Dürfen sie sich nicht überlappen? Dürfen sie nicht null sein? C (und die meisten C++ - Implementierungen) haben das Schlüsselwort restricted, beide haben Werttypen, C++ hat eine Referenz auf den Wert mit einer Garantie ungleich Null.Was bieten Java und C #?

>>>>>>>>>

Im Allgemeinen können C und C++ genauso schnell oder schneller sein, da der AOT-Compiler - ein Compiler, der Ihren Code vor der endgültigen Bereitstellung auf Ihrem Core-Build-Server mit hohem Arbeitsspeicher kompiliert - Optimierungen vornehmen kann, die ein C # -kompiliertes Programm vornimmt kann nicht, weil es eine Menge Zeit hat, dies zu tun. Der Compiler kann feststellen, ob es sich bei dem Computer um Intel oder AMD handelt. Pentium 4, Core Solo oder Core Duo; Wenn SSE4 usw. unterstützt wird und Ihr Compiler Runtime-Versand nicht unterstützt, können Sie dies selbst beheben, indem Sie eine Handvoll spezialisierter Binärdateien bereitstellen.

Das AC # -Programm wird normalerweise beim Ausführen kompiliert, damit es auf allen Computern einwandfrei ausgeführt werden kann. Es ist jedoch nicht so weit optimiert, wie es für eine einzelne Konfiguration (z. B. Prozessor, Befehlssatz, andere Hardware) möglich ist. muss zuerst etwas Zeit verbringen. Funktionen wie Schleifenspaltung, Schleifeninversion, automatische Vektorisierung, Optimierung des gesamten Programms, Vorlagenerweiterung, Börsengang und vieles mehr lassen sich nur schwer und vollständig auf eine Weise lösen, die den Endbenutzer nicht stört.

Zusätzlich erlauben bestimmte Sprachfunktionen dem Compiler in C++ oder C, Annahmen über Ihren Code zu treffen, die es ihm ermöglichen, bestimmte Teile zu optimieren, die für den Java/C # -Compiler einfach nicht sicher sind. Wenn Sie keinen Zugriff auf die vollständige Typ-ID von Generika oder einen garantierten Programmfluss haben, gibt es viele Optimierungen, die einfach nicht sicher sind.

Auch C++ und C führen mit nur einer Registerinkrementierung viele Stapelzuweisungen auf einmal durch, was sicherlich effizienter ist als Javas- und C # -Zuweisungen, was die Abstraktionsebene zwischen dem Garbage Collector und Ihrem Code betrifft.

Jetzt kann ich nicht für Java zu diesem nächsten Punkt sprechen, aber ich weiß, dass C++ - Compiler zum Beispiel tatsächlich Methoden und Methodenaufrufe entfernen, wenn sie wissen, dass der Hauptteil der Methode leer ist Vermeiden Sie häufige Unterausdrücke, versuchen Sie es erneut, um eine optimale Registernutzung zu finden, erzwingen Sie keine Begrenzungsüberprüfung, führen Sie eine automatische Vektorisierung von Schleifen und inneren Schleifen durch und kehren Sie innere zu äußeren Schleifen um, verschieben Sie Bedingungen aus Schleifen heraus, spalten Sie Schleifen auf und lösen Sie sie Erweitert std :: vector wie bei C zu systemeigenen Null-Overhead-Arrays, optimiert die Interprozedur, erstellt Rückgabewerte direkt an der Aufrufer-Site, faltet Ausdrücke und verteilt sie und ordnet sie neu an Eine Cache-freundliche Art. Es wird Jump-Threading ausführen. Es ermöglicht das Schreiben von Ray-Tracern zur Kompilierungszeit ohne Laufzeitaufwand. Es werden sehr teure graphbasierte Optimierungen durchgeführt. Es wird eine Reduzierung der Stärke vorgenommen, wenn bestimmte Codes syntaktisch völlig ungleich, aber sem ersetzt werden äquivalenter Code (der alte "xor foo, foo" ist nur der einfachste, wenn auch veraltete Code dieser Art). Wenn Sie dies bitte tun, können Sie IEEE-Gleitkommastandards weglassen und noch mehr Optimierungen wie die Neuordnung von Gleitkommaoperanden aktivieren. Nachdem der Code massiert und massakriert wurde, wird möglicherweise der gesamte Prozess wiederholt, da bestimmte Optimierungen häufig die Grundlage für noch sicherere Optimierungen bilden. Es könnte auch nur ein erneuter Versuch mit gemischten Parametern durchgeführt werden, um festzustellen, wie die andere Variante in ihrer internen Rangfolge abschneidet. Und diese Art von Logik wird in Ihrem gesamten Code verwendet.

Wie Sie sehen, gibt es viele Gründe, warum bestimmte C++ - oder C-Implementierungen schneller sind.

Nun, alles in allem können in C++ viele Optimierungen vorgenommen werden, die alles zunichte machen, was Sie mit C # tun können, insbesondere im Bereich der Zahlenverarbeitung, in Echtzeit und in der Nähe des Metals, aber nicht ausschließlich dort. Sie müssen nicht einmal einen einzigen Zeiger berühren, um einen langen Weg zurückzulegen.

Also, je nachdem, was Sie schreiben, würde ich mit dem einen oder anderen gehen. Aber wenn Sie etwas schreiben, das nicht hardwareabhängig ist (Treiber, Videospiel usw.), würde ich mir keine Sorgen um die Leistung von C # machen (ich kann wieder nicht über Java sprechen). Es wird gut gehen.

<<<<<<<<<<

Im Allgemeinen klingen bestimmte verallgemeinerte Argumente in bestimmten Posts vielleicht cool, aber im Allgemeinen klingen sie nicht unbedingt glaubwürdig.

Wie auch immer, um Frieden zu schließen: [~ # ~] aot [~ # ~] is great, as is [~ # ~] jit [~ # ~]. Die einzig richtige Antwort kann lauten: Es kommt darauf an. Und die wahren Schlauen wissen, dass man sowieso das Beste aus beiden Welten nutzen kann.

3
Sebastian Mach

Wenn Sie ein Java/C # -Programmierer sind, der C++ lernt, werden Sie versucht sein, weiter über Java/C # nachzudenken und wörtlich in C++ - Syntax zu übersetzen. In diesem Fall erhalten Sie nur die zuvor erwähnten Vorteile von nativem Code gegenüber interpretiertem/JIT. Um den größten Leistungsgewinn in C++ gegenüber Java/C # zu erzielen, müssen Sie lernen, in C++ zu denken und Code speziell zu entwerfen, um die Stärken von C++ zu nutzen.

Um Edsger Dijkstra zu paraphrasieren: [Ihre erste Sprache] verstümmelt den Geist bis zur Genesung.
Um Jeff Atwood zu paraphrasieren: Sie können [Ihre erste Sprache] in jeder neuen Sprache schreiben.

3
palm3D

Eine der wichtigsten JIT-Optimierungen ist das Inlining von Methoden. Java kann sogar virtuelle Methoden einbinden, wenn dies die Laufzeitkorrektheit gewährleistet. Diese Art der Optimierung kann normalerweise nicht von statischen Standardcompilern durchgeführt werden, da eine Analyse des gesamten Programms erforderlich ist, was aufgrund der getrennten Kompilierung schwierig ist ( Im Gegensatz dazu steht JIT das gesamte Programm zur Verfügung.) Durch Inlining von Methoden werden andere Optimierungen verbessert und größere Codeblöcke zur Optimierung bereitgestellt.

Die Standardspeicherzuweisung in Java/C # ist ebenfalls schneller und die Freigabe (Deallocation, GC) ist nicht viel langsamer, sondern nur weniger deterministisch.

3
user57697

Der aus einem Java oder C # -Compiler erzeugte ausführbare Code wird nicht interpretiert - er wird "just in time" (JIT) zu systemeigenem Code kompiliert. Somit ist der erste Zeitcode in einem Java/C # -Compiler Wenn ein Programm während der Ausführung angetroffen wird, entsteht ein gewisser Overhead, da der "Laufzeitcompiler" (auch als JIT-Compiler bezeichnet) den Bytecode (Java) oder den IL-Code (C #) in systemeigene Maschinenanweisungen umwandelt Die Anwendung wird noch ausgeführt, der native Code wird sofort ausgeführt. Dies erklärt, wie einige Java/C # -Programme anfangs langsam erscheinen, dann aber umso besser, je länger sie ausgeführt werden. Ein gutes Beispiel ist eine ASP.Net-Website. Das allererste Mal Der Zugriff auf die Website ist möglicherweise etwas langsamer, da der C # -Code vom JIT-Compiler zu systemeigenem Code kompiliert wird. Nachfolgende Zugriffe führen zu einer viel schnelleren Website - abgesehen vom Server- und Client-Caching.

3
Peter Meyer

Es ist unwahrscheinlich, dass die virtuellen Maschinensprachen kompilierte Sprachen übertreffen, aber sie können aus (zumindest) den folgenden Gründen so nahe kommen, dass es keine Rolle spielt (ich spreche hier für Java hier seit ich hab noch nie C # gemacht).

1/Die Java Runtime Environment ist normalerweise in der Lage, häufig ausgeführte Codeteile zu erkennen und Just-in-Time-Kompilierungen (JIT) dieser Abschnitte durchzuführen, damit sie in Zukunft auf ausgeführt werden die volle kompilierte Geschwindigkeit.

2/Große Teile der Bibliotheken Java) werden so kompiliert, dass beim Aufrufen einer Bibliotheksfunktion kompilierter Code ausgeführt wird, der nicht interpretiert wird. Sie können den Code (in C) durch Herunterladen anzeigen das OpenJDK.

3/Wenn Sie keine massiven Berechnungen durchführen, wartet Ihr Programm die meiste Zeit auf die Eingabe eines sehr langsamen (relativ) Menschen.

4/Da ein Großteil der Validierung von Java Bytecode zum Zeitpunkt des Ladens der Klasse erfolgt, wird der normale Aufwand für Laufzeitprüfungen erheblich reduziert.

5/Im schlimmsten Fall kann leistungsintensiver Code in ein kompiliertes Modul extrahiert und von Java (siehe JNI)) aufgerufen werden, damit er mit voller Geschwindigkeit ausgeführt wird.

Zusammenfassend lässt sich sagen, dass der Java Bytecode niemals die native Maschinensprache übertrifft, aber es gibt Möglichkeiten, dies zu mildern. Der große Vorteil von Java (wie ich es sehe) ist die RIESIGE Standardbibliothek und die plattformübergreifende Natur.

3
paxdiablo

Tatsächlich läuft C # nicht wirklich auf einer virtuellen Maschine wie Java). IL wird in Assembler kompiliert, der vollständig nativer Code ist und mit der gleichen Geschwindigkeit wie nativer Code ausgeführt wird. JIT ist eine .NET-Anwendung, die die JIT-Kosten vollständig beseitigt, und Sie führen dann vollständig systemeigenen Code aus.

Die Verlangsamung von .NET wird nicht dadurch verursacht, dass .NET-Code langsamer ist, sondern, dass es viel mehr hinter den Kulissen tut, um Dinge wie Garbage Collect, Überprüfen von Referenzen, Speichern vollständiger Stack-Frames usw. zu erledigen. Dies kann sehr leistungsstark und hilfreich sein, wenn Bauanwendungen, sondern kommt auch auf Kosten. Beachten Sie, dass Sie all diese Dinge auch in einem C++ - Programm ausführen können (ein Großteil der .NET-Kernfunktionalität besteht aus .NET-Code, den Sie in ROTOR anzeigen können). Wenn Sie jedoch dieselbe Funktionalität von Hand schreiben, erhalten Sie wahrscheinlich ein viel langsameres Programm, da die .NET-Laufzeit optimiert und fein abgestimmt wurde.

Das heißt, eine der Stärken von verwaltetem Code ist, dass er vollständig überprüfbar ist, d. H. Sie können sicherstellen, dass der Code niemals auf den Speicher eines anderen Prozesses zugreift oder Dinge nicht verwendet, bevor Sie ihn ausführen. Microsoft verfügt über einen Forschungsprototyp eines vollständig verwalteten Betriebssystems, der überraschenderweise gezeigt hat, dass eine zu 100% verwaltete Umgebung eine erheblich schnellere Leistung als jedes moderne Betriebssystem erzielen kann, indem diese Überprüfung genutzt wird, um Sicherheitsfunktionen zu deaktivieren, die von verwalteten Programmen nicht mehr benötigt werden (Wir sprechen in einigen Fällen wie 10x). SE Radio hat eine großartige Episode, in der es um dieses Projekt geht.

2
jezell

Dies würde nur passieren, wenn der Java) - Interpreter Maschinencode erzeugt, der tatsächlich besser optimiert ist als der Maschinencode, den Ihr Compiler für den C++ - Code generiert, den Sie schreiben der Punkt, an dem der C++ - Code langsamer ist als die Java und die Interpretationskosten.

Die Wahrscheinlichkeit, dass dies tatsächlich passiert, ist jedoch ziemlich gering - es sei denn, dass Java hat eine sehr gut geschriebene Bibliothek und Sie haben Ihre eigene schlecht geschriebene C++ - Bibliothek.

2
ine

Tatsächlich verwendet Suns HotSpot JVM die Ausführung im gemischten Modus. Es interpretiert den Bytecode der Methode, bis es (normalerweise über einen Zähler) feststellt, dass ein bestimmter Codeblock (Methode, Schleife, Try-Catch-Block usw.) häufig ausgeführt wird, und kompiliert ihn dann mit JIT. Die Zeit, die zum JIT-Kompilieren einer Methode erforderlich ist, dauert häufig länger, als wenn die Methode interpretiert werden müsste, wenn es sich um eine selten ausgeführte Methode handelt. Die Leistung im "gemischten Modus" ist normalerweise höher, da die JVM keine Zeit mit der Ausführung von JIT-Code verschwendet, der selten oder nie ausgeführt wird. C # und .NET tun dies nicht. .NET JITs alles, was oft Zeit verschwendet.

1
mcjabberz

Es kann zu kurzen Bursts kommen, wenn Java oder CLR schneller als C++ ist, die Leistung jedoch insgesamt für die Lebensdauer der Anwendung schlechter ist: siehe www.codeproject.com/KB/dotnet/RuntimePerformance.aspx für einige Ergebnisse dafür.

1
dmihailescu
1

Lesen Sie mehr über Dynamo von HP Labs, einen Interpreter für PA-8000, der auf PA-8000 ausgeführt wird und häufig Programme schneller ausführt als sie es von Haus aus tun. Dann scheint es gar nicht überraschend!

Betrachten Sie es nicht als "Zwischenschritt" - das Ausführen eines Programms umfasst bereits viele andere Schritte in einer beliebigen Sprache.

Es kommt oft darauf an:

  • programme haben Hotspots. Selbst wenn Sie 95% des Code-Körpers, den Sie ausführen müssen, langsamer ausführen, können Sie dennoch leistungsmäßig wettbewerbsfähig sein, wenn Sie schneller als 5% sind.

  • eine HLL weiß mehr über Ihre Absicht als eine LLL wie C/C++ und kann daher optimierten Code generieren (OCaml hat noch mehr und ist in der Praxis oft noch schneller).

  • ein JIT-Compiler hat viele Informationen, die ein statischer Compiler nicht hat (wie die tatsächlichen Daten, die Sie gerade haben).

  • ein JIT-Compiler kann zur Laufzeit Optimierungen vornehmen, die herkömmliche Linker eigentlich nicht zulassen (z. B. das Neuanordnen von Zweigen, um den allgemeinen Fall zu vereinfachen, oder das Inlinen von Bibliotheksaufrufen).

Alles in allem ist C/C++ eine ziemlich miese Sprache für die Leistung: Es gibt relativ wenig Informationen zu Ihren Datentypen, keine Informationen zu Ihren Daten und keine dynamische Laufzeit, die viel zur Laufzeitoptimierung beiträgt.

1
Ken

Ich verstehe, dass C/C++ nativen Code erzeugt, der auf einer bestimmten Maschinenarchitektur ausgeführt werden kann. Umgekehrt werden Sprachen wie Java und C # auf einer virtuellen Maschine ausgeführt, die die native Architektur abstrahiert. Logischerweise scheint es unmöglich, dass Java oder C # übereinstimmt die Geschwindigkeit von C++ aufgrund dieses Zwischenschritts, jedoch wurde mir gesagt, dass die neuesten Compiler ("Hot Spot") diese Geschwindigkeit erreichen oder sogar übertreffen können.

Das ist unlogisch. Die Verwendung einer Zwischendarstellung beeinträchtigt die Leistung nicht inhärent. Zum Beispiel kompiliert llvm-gcc C und C++ über LLVM IR (eine virtuelle Infinite-Register-Maschine) zu nativem Code und erzielt eine hervorragende Leistung (oftmals besser als GCC).

Vielleicht ist dies eher eine Compiler-Frage als eine Sprachfrage, aber kann jemand im Klartext erklären, wie es möglich ist, dass eine dieser virtuellen Maschinensprachen eine bessere Leistung erbringt als eine Muttersprache?

Hier sind einige Beispiele:

  • Virtuelle Maschinen mit JIT-Kompilierung erleichtern die Generierung von Laufzeitcode (z. B. System.Reflection.Emit on .NET), so dass Sie generierten Code in Sprachen wie C # und F # kompilieren können, aber auf das Schreiben eines vergleichsweise langsamen Interpreters in C oder C++ zurückgreifen müssen. Zum Beispiel, um reguläre Ausdrücke zu implementieren.

  • Teile der virtuellen Maschine (z. B. die Schreibsperre und der Zuweiser) werden häufig in handcodierten Assemblern geschrieben, da C und C++ nicht schnell genug Code generieren. Wenn ein Programm diese Teile eines Systems betont, kann es möglicherweise alles übertreffen, was in C oder C++ geschrieben werden kann.

  • Das dynamische Verknüpfen von nativem Code erfordert die Einhaltung einer ABI, die die Leistung beeinträchtigen und die Optimierung des gesamten Programms verhindern kann, wohingegen das Verknüpfen in der Regel auf VMs verzögert wird und von Optimierungen des gesamten Programms profitieren kann (wie bei .NETs überarbeiteten Generika).

Ich möchte auch einige Probleme mit Paercebals hochgelobter Antwort ansprechen (weil immer wieder jemand meine Kommentare zu seiner Antwort löscht), die eine kontraproduktiv polarisierte Sichtweise darstellen:

Die Code-Verarbeitung wird zum Zeitpunkt der Kompilierung durchgeführt ...

Daher funktioniert die Template-Metaprogrammierung nur, wenn das Programm zur Kompilierungszeit verfügbar ist, was häufig nicht der Fall ist, z. Es ist unmöglich, eine Bibliothek mit wettbewerbsfähigen regulären Ausdrücken in Vanilla C++ zu schreiben, da sie nicht in der Lage ist, Laufzeitcode zu generieren (ein wichtiger Aspekt der Metaprogrammierung).

... das Spielen mit Typen erfolgt zur Kompilierungszeit ... das Äquivalent in Java oder C # ist bestenfalls schmerzhaft zu schreiben und wird zur Laufzeit immer langsamer und aufgelöst, selbst wenn die Typen es sind zur Kompilierzeit bekannt.

In C # gilt dies nur für Referenztypen und nicht für Werttypen.

Unabhängig von der JIT-Optimierung ist nichts schneller als ein direkter Zeigerzugriff auf den Speicher. Wenn sich zusammenhängende Daten im Speicher befinden, kann der Zugriff über C++ - Zeiger (dh C-Zeiger) schneller erfolgen als in Java/C #.

Die Leute haben Java schlägt C++ beim SOR-Test des SciMark2-Benchmarks genau deshalb beobachtet, weil Zeiger Optimierungen im Zusammenhang mit Aliasing behindern.

Erwähnenswert ist auch, dass .NET nach dem Verknüpfen eine Typenspezialisierung von Generika für dynamisch verknüpfte Bibliotheken durchführt, wohingegen C++ dies nicht kann, da Vorlagen vor dem Verknüpfen aufgelöst werden müssen. Und der große Vorteil, den Generika gegenüber Vorlagen haben, sind verständliche Fehlermeldungen.

1
Jon Harrop

In einigen Fällen kann verwalteter Code tatsächlich schneller sein als nativer Code. Beispielsweise ermöglichen "Mark-and-Sweep" -Garbage-Collection-Algorithmen Umgebungen wie JRE oder CLR, eine große Anzahl kurzlebiger (normalerweise) Objekte in einem Durchgang freizugeben, wobei die meisten C/C++ - Heap-Objekte einzeln freigegeben werden. eine Zeit.

Aus Wikipedia :

Für viele praktische Zwecke können zuweisungs-/zuweisungsintensive Algorithmen, die in Sprachen mit Speicherbereinigung implementiert sind, mithilfe der manuellen Heapzuweisung tatsächlich schneller als ihre Entsprechungen sein. Ein Hauptgrund dafür ist, dass der Garbage Collector es dem Laufzeitsystem ermöglicht, Allokations- und Freigabevorgänge auf eine potenziell vorteilhafte Weise abzuschreiben.

Trotzdem habe ich viel C # und viel C++ geschrieben und viele Benchmarks durchgeführt. Nach meiner Erfahrung ist C++ in zweierlei Hinsicht viel schneller als C #: (1) Wenn Sie Code verwenden, den Sie in C # geschrieben haben, portieren Sie ihn in C++. Der native Code tendiert schneller sein. Wie viel schneller? Nun, es ist sehr unterschiedlich, aber es ist nicht ungewöhnlich, dass sich die Geschwindigkeit um 100% verbessert. (2) In einigen Fällen kann die Garbage Collection eine verwaltete Anwendung massiv verlangsamen. Die .NET-CLR leistet bei großen Haufen (z. B.> 2 GB) schreckliche Arbeit und kann viel Zeit in der GC verbringen - selbst in Anwendungen mit wenigen oder gar keinen Objekten mit einer mittleren Lebensdauer.

Natürlich sind verwaltete Sprachen in den meisten Fällen, auf die ich gestoßen bin, bei weitem nicht schnell genug, und der Kompromiss zwischen Wartung und Codierung für die zusätzliche Leistung von C++ ist einfach nicht gut.

1
cero

Für alles, was viel Geschwindigkeit benötigt, ruft die JVM einfach eine C++ - Implementierung auf. Es geht also eher darum, wie gut ihre Bibliotheken sind, als wie gut die JVM für die meisten betriebssystembezogenen Dinge ist. Die Speicherbereinigung halbiert Ihren Speicherplatz, aber die Verwendung einiger der schickeren STL- und Boost-Funktionen hat den gleichen Effekt, jedoch mit dem Vielfachen des Fehlerpotenzials.

Wenn Sie in einem großen Projekt mit vielen Klassen nur C++ - Bibliotheken und viele Funktionen auf hoher Ebene verwenden, werden Sie wahrscheinlich langsamer als mit einer JVM. Außer viel fehleranfälliger.

Der Vorteil von C++ besteht jedoch darin, dass Sie sich selbst optimieren können, da Sie sonst nicht mehr mit den Aufgaben des Compilers/jvm zufrieden sind. Wenn Sie Ihre eigenen Container erstellen, Ihre eigene Speicherverwaltung schreiben, SIMD verwenden und hier und da zu Assembly wechseln, können Sie mindestens das 2-fache der Geschwindigkeit erreichen, die die meisten C++ - Compiler für sich selbst ausführen. Für einige Operationen 16x-32x. Das sind die gleichen Algorithmen. Wenn Sie bessere Algorithmen verwenden und parallelisieren, können Erhöhungen dramatisch sein, manchmal tausende Male schneller als die üblicherweise verwendeten Methoden.

0

Ich denke nicht, dass die Leistung heutzutage in Bezug auf die Verarbeitungsgeschwindigkeit des Servers berücksichtigt werden muss (schließlich sind die Multi-Core-Prozessoren auf dem Markt). Es sollte auf der Grundlage der Speichernutzung genauer definiert werden. Und auf diese Weise hat Java einen kleinen Nachteil.
Trotzdem sind alle Programmiersprachen für verschiedene Zwecke geeignet. Und das ist ihr Wettbewerbsbereich, in jeder Sektion gibt es unterschiedliche Gewinner.
Und ich bin sicher, dass Java auf lange Sicht gewinnen wird, weil es die Entwicklung und Wettbewerbsfähigkeit fortsetzt, die es in all den neuen Funktionen zeigt, die es hervorbringt.
Ich habe hier einen Link gefunden, der meinen Grund für die Wahl von Java stützt

0
Naveen Babu

Eine sehr kurze Antwort: Bei einem festgelegten Budget erzielen Sie eine leistungsfähigere Java) -Anwendung als eine C++ - Anwendung (ROI-Überlegungen). Außerdem verfügt die Java) -Plattform über anständigere Profiler Dies hilft Ihnen dabei, Ihre Hotspots schneller zu lokalisieren

0
lifey

Ich schaue es aus ein paar verschiedenen Blickwinkeln an.

  1. Wird verwalteter oder nicht verwalteter Code bei unendlich viel Zeit und Ressourcen schneller sein? Die Antwort ist eindeutig, dass nicht verwalteter Code in dieser Hinsicht immer mindestens verwalteten Code binden kann - wie im schlimmsten Fall, würden Sie die Lösung für verwalteten Code nur hart codieren.
  2. Wenn Sie ein Programm in einer Sprache nehmen und es direkt in eine andere übersetzen, um wie viel schlechter wird es dann funktionieren? Wahrscheinlich viel, für beliebige zwei Sprachen. Die meisten Sprachen erfordern unterschiedliche Optimierungen und haben unterschiedliche Fallstricke. Bei der Mikro-Performance geht es oft darum, diese Details zu kennen.
  3. Welche der beiden Sprachen liefert angesichts der begrenzten Zeit und Ressourcen ein besseres Ergebnis? Dies ist die interessanteste Frage, da eine verwaltete Sprache zwar etwas langsameren Code produzieren kann (vorausgesetzt, ein Programm ist für diese Sprache angemessen geschrieben), diese Version jedoch wahrscheinlich früher erstellt wird, wodurch mehr Zeit für die Optimierung aufgewendet wird.
0
kyoryu

Nach meinem Verständnis sind .NET und Java besser in der Speicherzuordnung. Beispielsweise können sie Speicher komprimieren, da er fragmentiert wird, während C++ dies nicht kann (nativ, aber wenn ja) Sie benutzen einen cleveren Müllsammler).

0
Giovanni Galbo