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


119

Nach meinem Verständnis erzeugt C / C ++ nativen Code, der auf einer bestimmten Maschinenarchitektur ausgeführt werden kann. Umgekehrt laufen Sprachen wie Java und C # auf einer virtuellen Maschine, die die native Architektur abstrahiert. Logischerweise scheint es Java oder C # aufgrund dieses Zwischenschritts unmöglich zu sein, die Geschwindigkeit von C ++ zu erreichen. Mir wurde jedoch gesagt, dass die neuesten Compiler ("Hot Spot") diese Geschwindigkeit erreichen oder sogar überschreiten können.

Vielleicht ist dies eher eine Compiler-Frage als eine Sprachfrage, aber kann jemand im Klartext erklären, wie eine dieser Sprachen der virtuellen Maschine eine bessere Leistung als eine Muttersprache erzielen kann?


Java und C # können eine Optimierung basierend auf der tatsächlichen Ausführung der Anwendung mithilfe des Codes vornehmen, der zur Laufzeit verfügbar ist. Beispielsweise kann es Code in eine gemeinsam genutzte Bibliothek einbinden, der sich tatsächlich ändern kann, während das Programm ausgeführt wird und dennoch korrekt ist.
Peter Lawrey

Einige aktuelle Messungen zu überprüfen , bevor eine Menge sehr flockig Theorie in diese Antworten zu lesen: shootout.alioth.debian.org/u32/...
Justicle

Antworten:


178

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

Ein C ++ - Programm muss normalerweise vorher mit gemischten Optimierungen kompiliert werden, damit es auf allen Computern anständig läuft, aber nicht so stark optimiert ist, wie es für eine einzelne Konfiguration (dh Prozessor, Befehlssatz, andere Hardware) sein könnte.

Darüber hinaus ermöglichen 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. Wenn Sie Zugriff auf Zeiger haben, gibt es viele Optimierungen, die einfach nicht sicher sind.

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

Jetzt kann ich in diesem nächsten Punkt nicht für Java sprechen, aber ich weiß, dass C # beispielsweise tatsächlich Methoden und Methodenaufrufe entfernt, wenn es weiß, dass der Hauptteil der Methode leer ist. Und es wird diese Art von Logik in Ihrem gesamten Code verwenden.

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

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

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.

Auf der Java-Seite weist @Swati auf einen guten Artikel hin:

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


Ihre Argumentation ist falsch - C ++ - Programme werden für ihre Zielarchitektur erstellt und müssen zur Laufzeit nicht gewechselt werden.
Justicle

3
@Justicle Das Beste, was Ihr C ++ - Compiler für verschiedene Architekturen bietet, ist normalerweise x86, x64, ARM und so weiter. Jetzt können Sie festlegen, dass bestimmte Funktionen verwendet werden sollen (z. B. SSE2). Wenn Sie Glück haben, wird sogar ein Sicherungscode generiert, wenn diese Funktion nicht verfügbar ist, aber das ist ungefähr so ​​detailliert wie möglich. Sicherlich keine Spezialisierung abhängig von Cache-Größen und so weiter.
Voo

4
Siehe shootout.alioth.debian.org/u32/... Beispiele für diese Theorie nicht geschieht.
Justicle

1
Um ehrlich zu sein, ist dies eine der schlechtesten Antworten. Es ist so unbegründet, dass ich es einfach umkehren könnte. Zu viel Verallgemeinerung, zu viel Unwissen (die Optimierung leerer Funktionen ist eigentlich nur die Spitze des Eisbergs). Ein Luxus-C ++ - Compiler hat: Zeit. Ein weiterer Luxus: Es wird keine Überprüfung erzwungen. Weitere Informationen finden Sie unter stackoverflow.com/questions/145110/c-performance-vs-java-c/… .
Sebastian Mach

1
@OrionAdrian ok Wir sind der Kreis jetzt ... Siehe shootout.alioth.debian.org/u32/... Beispiele für diese Theorie nicht geschieht. Zeigen Sie uns mit anderen Worten, dass Ihre Theorie als richtig erwiesen werden kann, bevor Sie vage spekulative Aussagen treffen.
Justicle

197

JIT vs. Static Compiler

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

JIT hat ein großes Problem: Es kann nicht alles kompilieren: Das Kompilieren von JIT braucht Zeit, daher kompiliert das JIT nur einige Teile des Codes, während ein statischer Compiler eine vollständige native Binärdatei erzeugt: Für einige Programme die statische Der Compiler übertrifft die JIT einfach leicht.

Natürlich ist C # (oder Java oder VB) normalerweise schneller, um eine tragfähige und robuste Lösung zu erstellen als C ++ (schon allein deshalb, weil C ++ eine komplexe Semantik aufweist und die C ++ - Standardbibliothek zwar interessant und leistungsfähig ist, aber im Vergleich zur vollständigen Bibliothek ziemlich schlecht Umfang der Standardbibliothek von .NET oder Java), daher ist der Unterschied zwischen C ++ und .NET oder Java JIT für die meisten Benutzer normalerweise nicht sichtbar, und für die kritischen Binärdateien können Sie weiterhin die C ++ - Verarbeitung aufrufen von C # oder Java (auch wenn diese Art von nativen Aufrufen an sich ziemlich kostspielig sein kann) ...

C ++ - Metaprogrammierung

Beachten Sie, dass Sie normalerweise C ++ - Laufzeitcode mit dem entsprechenden Code in C # oder Java vergleichen. C ++ verfügt jedoch über eine Funktion, die Java / C # sofort übertreffen kann, nämlich das Metaprogrammieren von Vorlagen: Die Codeverarbeitung erfolgt zur Kompilierungszeit (wodurch die Kompilierungszeit erheblich verlängert wird), was zu einer Laufzeit von null (oder fast null) führt.

Ich habe noch keinen realen Effekt darauf gesehen (ich habe nur mit Konzepten gespielt, aber bis dahin war der Unterschied Sekunden der Ausführung für JIT und Null für C ++), aber dies ist erwähnenswert, neben der Tatsache, dass Metaprogrammierung nicht der Fall ist trivial...

Edit 2011-06-10: In C ++ wird das Spielen mit Typen zur Kompilierungszeit ausgeführt, dh es wird generischer Code erstellt, der nicht generischen Code aufruft (z. B. ein generischer Parser von Zeichenfolge zu Typ T, der die Standardbibliotheks-API für die erkannten Typen T aufruft). und den Parser für seinen Benutzer leicht erweiterbar zu machen) ist sehr einfach und sehr effizient, während das Äquivalent in Java oder C # bestenfalls schmerzhaft zu schreiben ist und zur Laufzeit immer langsamer und aufgelöst wird, selbst wenn die Typen zur Kompilierungszeit bekannt sind. Das heißt, Ihre einzige Hoffnung ist, dass die GEG das Ganze inline macht.

...

Edit 2011-09-20: Das Team hinter Blitz ++ ( Homepage , Wikipedia ) ist diesen Weg gegangen, und anscheinend ist es ihr Ziel, die Leistung von FORTRAN bei wissenschaftlichen Berechnungen zu erreichen, indem es so weit wie möglich von der Laufzeitausführung zur Kompilierungszeit über die Metaprogrammierung von C ++ - Vorlagen übergeht . Der Teil " Ich habe noch so einen realen Effekt auf diesen " gesehen, den ich oben geschrieben habe, existiert anscheinend im realen Leben.

Native C ++ - Speichernutzung

C ++ hat eine andere Speichernutzung als Java / C # und daher unterschiedliche Vorteile / Mängel.

Unabhängig von der JIT-Optimierung ist nichts so schnell wie der direkte Zeigerzugriff auf den Speicher (ignorieren wir für einen Moment Prozessor-Caches usw.). Wenn Sie also zusammenhängende Daten im Speicher haben, geht der Zugriff auf diese über C ++ - Zeiger (dh C-Zeiger ... Geben wir Caesar die Schuld) schneller als in Java / C #. Und C ++ hat RAII, was die Verarbeitung erheblich vereinfacht als in C # oder sogar in Java. C ++ muss usingdie Existenz seiner Objekte nicht erfassen . Und C ++ hat keine finallyKlausel. Dies ist kein Fehler.

:-)

Und trotz C # -primitiver Strukturen kosten C ++ "on the stack" -Objekte bei Zuweisung und Zerstörung nichts und benötigen keinen GC, um in einem unabhängigen Thread für die Bereinigung zu arbeiten.

Was die Speicherfragmentierung betrifft, so sind Speicherzuordnungen im Jahr 2008 nicht die alten Speicherzuordnungen aus dem Jahr 1980, die normalerweise mit einer GC: C ++ - Zuweisung verglichen werden. Sie können zwar nicht in den Speicher verschoben werden, aber wie bei einem Linux-Dateisystem: Wer benötigt eine Festplatte? Defragmentierung, wenn keine Fragmentierung stattfindet? Die Verwendung des richtigen Allokators für die richtige Aufgabe sollte Teil des C ++ - Entwickler-Toolkits sein. Das Schreiben von Allokatoren ist nicht einfach, 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.

Edit 2011-10-04: Beispiele für effiziente Allokatoren: Auf Windows-Plattformen ist seit Vista der Heap mit geringer Fragmentierung standardmäßig aktiviert. Für frühere Versionen kann der LFH durch Aufrufen der WinAPI-Funktion HeapSetInformation aktiviert werden . Auf anderen Betriebssystemen werden alternative Allokatoren bereitgestellt (siehehttps://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 hat, wie mir gesagt wurde, die Oberhand behalten. Für einige "on the bare metal" -Hacker ist es einfach, seinen Code "in der Nähe der Maschine" zu loben. Jetzt ist es jedoch schwieriger, eine bessere Assembly von Hand zu erstellen, als den Compiler seiner Arbeit zu überlassen. Für C ++ wurde der Compiler seit einem Jahrzehnt normalerweise besser als der Hacker. Für C # und Java ist dies noch einfacher.

Der neue Standard C ++ 0x wird C ++ - Compilern jedoch 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 eingehalten werden.

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

Hinweis: In diesem Abschnitt geht es um C ++ / CLI, dh das von .NET gehostete C ++, nicht das native 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.

Der gleiche Code, der in C ++ / CLI kompiliert wurde (oder sein Vorgänger, Managed C ++), kann zeitweise schneller sein als der gleiche Code, der in C # (oder VB.NET, dessen Compiler dieselbe IL als C # erzeugt) erzeugt wurde.

Weil der statische C ++ - Compiler viel besser war, um bereits optimierten Code zu erzeugen als den von C #.

Beispielsweise ist das Inlining von Funktionen in .NET auf Funktionen beschränkt, deren Bytecode kleiner oder gleich 32 Byte lang ist. Ein Code in C # erzeugt also einen 40-Byte-Accessor, der von der JIT niemals eingebunden wird. Der gleiche Code in C ++ / CLI erzeugt einen 20-Byte-Accessor, der von der JIT eingebunden wird.

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

Es wurde spekuliert, dass der C ++ / CLI-Compiler von den umfangreichen Optimierungstechniken des nativen C ++ - Compilers profitierte.

Fazit

Ich liebe C ++.

Aber meines Erachtens sind C # oder Java insgesamt eine bessere Wahl. Nicht weil sie schneller als C ++ sind, sondern weil sie, wenn Sie ihre Qualitäten addieren, produktiver sind, weniger Schulung benötigen und vollständigere Standardbibliotheken als C ++ haben. Und wie bei den meisten Programmen sind ihre Geschwindigkeitsunterschiede (auf die eine oder andere Weise) vernachlässigbar ...

Bearbeiten (2011-06-06)

Meine Erfahrung mit C # /. NET

Ich habe jetzt 5 Monate fast ausschließlich professionelle C # -Codierung (was zu meinem Lebenslauf führt, der bereits voll mit C ++ und Java und einem Hauch von C ++ / CLI ist).

Ich habe mit WinForms (Ahem ...) und WCF (cool!) Und WPF (Cool !!!! sowohl über XAML als auch über rohes C # gespielt. WPF ist so einfach, dass Swing meiner Meinung nach 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 # (und noch schwieriger in Java) als in C ++ zu erstellen. 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 Analysemethode (von Zeichenfolge bis 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 lösen) und behandelt nur den Speicher. Selbst C # usingist nicht so einfach und leistungsstark, da das Schreiben korrekter Dispose-Implementierungen schwierig ist ).
  3. C # readonlyund Java finalsind nirgends so nützlich wie in C ++const (es gibt keine Möglichkeit, schreibgeschützte komplexe Daten (z. B. einen Baum von Knoten) in C # ohne großen Aufwand 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, also ist es bei weitem nicht genug ).

C # bleibt also eine angenehme Sprache, solange Sie etwas wollen, das funktioniert, aber eine frustrierende Sprache, sobald Sie etwas wollen, das immer und sicher funktioniert.

Java ist noch frustrierender, da es die gleichen Probleme wie C # hat und mehr: Ohne das Äquivalent des usingSchlüsselworts von C # hat ein sehr erfahrener Kollege von mir zu viel Zeit darauf verwendet, sicherzustellen, dass seine Ressourcen korrekt freigegeben wurden, während dies bei C ++ der Fall wäre war einfach (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 ...).

Informationen zu serverseitigem Java und C ++

Ich hielt Kontakt zu den Serverteams (ich habe 2 Jahre unter ihnen gearbeitet, bevor ich zum GUI-Team zurückkehrte) auf der anderen Seite des Gebäudes und lernte etwas Interessantes.

In den letzten Jahren bestand der Trend darin, dass die Java-Server-Apps die alten C ++ - Server-Apps ersetzen sollten, da Java über viele Frameworks / Tools verfügt und einfach zu warten, bereitzustellen usw. usw. ist.

... Bis das Problem der geringen Latenz in den letzten Monaten seinen hässlichen Kopf aufrichtete. Dann haben die Java-Server-Apps, unabhängig von der von unserem erfahrenen Java-Team versuchten Optimierung, einfach und sauber das Rennen gegen den alten, nicht wirklich optimierten C ++ - Server verloren.

Derzeit besteht die Entscheidung darin, die Java-Server für den allgemeinen Gebrauch zu behalten, wenn die Leistung zwar noch wichtig ist, jedoch nicht vom Ziel mit geringer Latenz betroffen ist, und die bereits schnelleren C ++ - Serveranwendungen aggressiv für Anforderungen mit geringer Latenz und extrem geringer Latenz zu optimieren.

Fazit

Nichts ist so einfach wie erwartet.

Java und noch mehr C # sind coole Sprachen mit umfangreichen Standardbibliotheken und Frameworks, in denen Sie schnell codieren können und sehr bald Ergebnisse erzielen.

Wenn Sie jedoch rohe Leistung, leistungsstarke und systematische Optimierungen, starke Compiler-Unterstü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, um sich von der Konkurrenz abzuheben.

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

Dies ist natürlich meine eigene Wahrnehmung, die möglicherweise auf unsere spezifischen Bedürfnisse beschränkt ist.

Aber genau das passiert heute, sowohl in den GUI-Teams als auch in den serverseitigen Teams.

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

Bearbeiten (22.06.2011)

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

[...] Die Java-Version war wahrscheinlich am einfachsten zu implementieren, aber am schwierigsten auf Leistung zu analysieren. Insbesondere die Auswirkungen der Speicherbereinigung waren kompliziert und sehr schwer abzustimmen. "

Quellen:

Bearbeiten (20.09.2011)

"Das Schlagwort bei Facebook ist, dass ' vernünftigerweise geschriebener C ++ - Code nur schnell läuft ', 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 ein viel einfacher [in C ++ als in anderen Sprachen zu schreiben]. "

- Herb Sutter bei // build / unter Angabe von Andrei Alexandrescu

Quellen:


8
Sie bearbeiten nach 5 Monaten C # beschreibt genau meine eigene Erfahrung (Vorlagen besser, const besser, RAII). +1. Diese drei bleiben meine persönlichen Killer-Features für C ++ (oder D, für die ich noch keine Zeit hatte).
Sebastian Mach

"Die Codeverarbeitung erfolgt zur Kompilierungszeit". Daher ist die Template-Metaprogrammierung, die nur im Programm funktioniert, zur Kompilierungszeit verfügbar, was häufig nicht der Fall ist. Beispielsweise ist es unmöglich, eine wettbewerbsfähig performante Bibliothek für reguläre Ausdrücke in Vanilla C ++ zu schreiben, da sie nicht in der Lage ist, Laufzeitcode zu generieren (ein wichtiger Aspekt von Metaprogrammierung).
JD

"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 zur Kompilierungszeit bekannt sind." In C # gilt dies nur für Referenztypen und nicht für Werttypen.
JD

1
"Unabhängig von der JIT-Optimierung wird nichts so schnell gehen wie der direkte Zeigerzugriff auf den Speicher ... Wenn Sie zusammenhängende Daten im Speicher haben, wird der Zugriff über C ++ - Zeiger (dh C-Zeiger ... Geben wir Caesar die Schuld) mal gehen schneller als in Java / C # ". Menschen haben beobachtet, wie Java beim SOR-Test aus dem SciMark2-Benchmark C ++ schlug, gerade weil Zeiger Aliasing-bezogene Optimierungen behindern. blogs.oracle.com/dagastine/entry/sun_java_is_faster_than
JD

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

48

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 dieser Google-Suche können Sie selbst lesen, aber ich mag Ricos Zusammenfassung.

Schäme ich mich für meine vernichtende Niederlage? Kaum. Der verwaltete Code erzielte ohne großen Aufwand ein sehr gutes Ergebnis. Um den gemanagten Raymond zu besiegen, musste:

  • Schreiben Sie seine eigenen Datei-E / A-Sachen
  • Schreiben Sie seine eigene String-Klasse
  • Schreiben Sie seinen eigenen Allokator
  • Schreiben Sie sein eigenes internationales Mapping

Natürlich hat er dafür verfügbare Bibliotheken niedrigerer Ebenen verwendet, aber das ist immer noch viel Arbeit. Können Sie aufrufen, was noch 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 find-Funktion beibehalten. So ziemlich alles andere ist weg.

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

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

Für mich ist das Fazit, 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 die letzte Leistung benötigen (und die Zeit und das Fachwissen haben, um sie zu erhalten), müssen Sie nicht verwaltet werden, aber für mich werde ich den Vorteil in der Größenordnung nutzen, den ich bei den ersten Versionen gegenüber den 33 habe % Ich gewinne, wenn ich es 6 Mal versuche.


3
Link ist tot, gefundener Artikel hier gefunden: blogs.msdn.com/b/ricom/archive/2005/05/10/416151.aspx
gjvdkamp

Wenn wir uns den Code von Raymond Chen ansehen, versteht er C ++ oder Datenstrukturen eindeutig nicht sehr gut. Sein Code greift fast direkt auf C-Code auf niedriger Ebene zu, selbst wenn der C-Code keine Leistungsvorteile bietet (es scheint nur eine Art Misstrauen und möglicherweise ein Mangel an Wissen über die Verwendung von Profilern zu sein). Er verstand auch nicht die algorithmisch fundierteste Art, ein Wörterbuch zu implementieren (er benutzte std :: find um Christi willen). Wenn Java, Python, C # usw. etwas Gutes haben - alle bieten sehr effiziente Wörterbücher ...
stinky472

Versuche oder sogar std :: map würden in Bezug auf C ++ oder sogar eine Hash-Tabelle viel günstiger abschneiden. Schließlich ist ein Wörterbuch genau die Art von Programm, die am meisten von Bibliotheken und Frameworks auf hoher Ebene profitiert. Es zeigt weniger Unterschiede in der Sprache als in den beteiligten Bibliotheken (von denen ich gerne sagen würde, dass C # weitaus vollständiger ist und viel mehr Werkzeuge bietet, die für die Aufgabe geeignet sind). Zeigen Sie ein Programm, das im Vergleich große Speicherblöcke manipuliert, wie z. B. einen großen Matrix- / Vektorcode. Das wird das ziemlich schnell erledigen, selbst wenn die Codierer, wie in diesem Fall, nicht wissen, was ...
stinky472

26

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 fast keine. Die meisten Leistungsunterschiede können nur bei Verwendung skalarer Datenverarbeitungsfunktionen beobachtet werden. Dies erfordert möglicherweise eine manuelle Feinabstimmung, um ohnehin maximale Leistung zu erzielen. Optimierungen dieser Art sind langsam und kostenintensiv und daher für JIT manchmal sowieso ungeeignet.

In der realen Welt und in realen Anwendungen ist C ++ normalerweise 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 dafür müssen Sie Ihr Gehirn einsetzen. C ++ ist eine Sprache, die beschlossen hat, Ihnen mehr Tools zur Verfügung zu stellen, wobei der Preis berechnet wird, den Sie lernen müssen, um die Sprache gut verwenden zu können.


4
Es ist nicht so sehr, dass Sie für die CPU-Optimierung kompilieren, sondern für die Laufzeitpfadoptimierung. Wenn Sie feststellen, dass eine Methode sehr oft mit einem bestimmten Parameter aufgerufen wird, können Sie diese Routine mit diesem Parameter als Konstante vorkompilieren, die (im Fall eines Booleschen Werts, der den Fluss steuert) gigantische Arbeitsblöcke herausrechnen kann. C ++ kann dieser Art der Optimierung nicht nahe kommen.
Bill K

1
Wie verhalten sich JITs beim Neukompilieren von Routinen, um die beobachteten Laufpfade zu nutzen, und wie viel Unterschied macht das?
David Thornley

2
@ Bill Ich mische vielleicht zwei Dinge ... aber wird die Verzweigungsvorhersage nicht zur Laufzeit in der Anweisungspipeline durchgeführt, um ähnliche Ziele unabhängig von der Sprache zu erreichen?
Hardy

@Hardy Ja, die CPU kann unabhängig von der Sprache eine Verzweigungsvorhersage durchführen, aber sie kann nicht eine gesamte Schleife herausrechnen, indem sie beobachtet, dass die Schleife keine Auswirkung auf irgendetwas hat. Es wird auch nicht beobachtet, dass mult (0) fest verdrahtet ist, um 0 zurückzugeben und einfach den gesamten Methodenaufruf durch if (param == 0) result = 0 zu ersetzen; und vermeiden Sie den gesamten Funktions- / Methodenaufruf. C könnte diese Dinge tun, wenn der Compiler einen umfassenden Überblick über das Geschehen hätte, aber im Allgemeinen nicht genügend Informationen zur Kompilierungszeit hat.
Bill K

21

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

Dies bedeutet, dass es jeden Compiler-Trick nutzen kann, den Ihre CPU unterstützen kann, unabhängig davon, auf welche CPU der Entwickler den Code geschrieben hat.

Das Grundkonzept der .NET JIT funktioniert folgendermaßen (stark vereinfacht):

Zum ersten Mal eine Methode aufrufen:

  • Ihr Programmcode ruft eine Methode Foo () auf
  • Die CLR untersucht den Typ, der Foo () implementiert, und ruft die damit verbundenen Metadaten ab
  • Aus den Metadaten weiß die CLR, in welcher Speicheradresse die IL (Intermediate Byte Code) gespeichert ist.
  • Die CLR weist einen Speicherblock zu und ruft die JIT auf.
  • Die JIT kompiliert die IL in nativen Code, legt sie im zugewiesenen Speicher ab und ändert dann den Funktionszeiger in den Metadaten vom Typ Foo (), um auf diesen nativen Code zu verweisen.
  • Der native Code wird ausgeführt.

Zum zweiten Mal eine Methode 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 können, ist es beim zweiten Mal praktisch der gleiche Prozess wie in C ++, außer mit dem Vorteil von Echtzeitoptimierungen.

Trotzdem gibt es noch andere Overhead-Probleme, die eine verwaltete Sprache verlangsamen, aber die JIT hilft sehr.


Übrigens, Jonathan, ich denke, jemand stimmt deine Sachen immer noch ab. Als ich dich gewählt habe, hattest du eine -1 in diesem Beitrag.
Brian R. Bondy

12

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

Die gleiche Frage wurde vor Jahrzehnten über Assemblersprache im Vergleich zu "menschlichen" Sprachen wie FORTRAN gestellt. Und ein Teil der Antwort ist ähnlich.

Ja, ein C ++ - Programm kann mit einem bestimmten (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 die C # -Version möglicherweise immer noch um einen sehr 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 "realen" Problemen (für mich persönlich bedeutet das "die Art, für deren Lösung ich bezahlt werde") wird C # die Arbeit schneller und sicherer erledigen.

Die größte Strafe, die Sie zahlen? Viele .NET- und Java-Programme sind Speicherfresser. Ich habe gesehen, dass .NET- und Java-Apps "Hunderte" Megabyte Speicher benötigen, wenn C ++ - Programme mit ähnlicher Komplexität kaum die "Zehn" MBs zerkratzen.


7

Ich bin mir nicht sicher, wie oft Sie feststellen werden, dass Java-Code selbst mit Hotspot schneller als C ++ ausgeführt wird, aber ich werde versuchen, zu erklären, wie dies passieren könnte.

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 mehrmals verwendet werden, führt er eine Optimierung des Maschinencodes durch. Da die Hand-Tuning-Assembly fast immer schneller ist als C ++ - kompilierter Code, kann man sich vorstellen, dass programmgesteuerter Maschinencode nicht allzu schlecht sein wird.

Bei sich stark wiederholendem Code konnte ich also sehen, wo Hotspot JVM Java schneller als C ++ ausführen kann ... bis die Garbage Collection ins Spiel kommt. :) :)


Könnten Sie die Behauptung erweitern Since hand-tuning Assembly is almost always faster than C++ compiled code? Was meinen Sie mit "Hand-Tuning Assembly" und "C ++ - kompiliertem Code"?
Paercebal

Nun, es basiert auf der Idee, dass der Optimierer eines Compilers Regeln folgt und Codierer dies nicht tun. Es wird also immer Code geben, den der Optimierer nicht perfekt optimieren kann, wohingegen ein Mensch dies tun könnte, indem er entweder ein größeres Bild betrachtet oder mehr darüber weiß, was der Code wirklich tut. Ich füge hinzu, dass dies ein 3 Jahre alter Kommentar ist und ich mehr über HotSpot weiß als früher, und ich kann leicht sehen, dass die dynamische Optimierung eine SEHR gute Möglichkeit ist, Code schneller zum Laufen zu bringen.
Billjamesdev

1. Optimierungen von Hotspot oder einem anderen JIT sind weiterhin Compiler-Optimierungen. JIT hat gegenüber einem statischen Compiler den Vorteil, dass einige Ergebnisse (häufig aufgerufener Code) eingebunden oder sogar Optimierungen basierend auf dem ausführenden Prozessor vorgenommen werden können. Es handelt sich jedoch immer noch um eine Compileroptimierung. . . 2. Ich denke, Sie sprechen von Algorithmusoptimierung, nicht von "Feinabstimmung der Baugruppe". "Feinabstimmung der manuellen Montage durch einen menschlichen Codierer" konnte seit mehr als einem Jahrzehnt keine besseren Ergebnisse als Compiler-Optimierungen erzielen. Tatsächlich
schraubt

Ok, ich verstehe, dass ich die falsche Terminologie verwende, "Compiler-Optimierung" statt "statische Optimierung". Ich möchte darauf hinweisen, dass wir zumindest in der Spielebranche noch vor kurzem für die PS2 handcodierte Baugruppen verwendet haben, um die spezifischen Chips, von denen wir wussten, dass sie sich auf der Konsole befinden, zu "optimieren". Cross-Compiler für diese neuen Chips sind noch nicht so ausgefeilt wie für x86-Architekturen. Zurück zur ursprünglichen Frage oben: Die JIT hat den Vorteil, dass sie vor der Optimierung messen kann, was eine gute Sache (TM) ist
billjamesdev

Beachten Sie, dass die meisten Produktions-GCs auch handgeschriebene Assembler verwenden, da C / C ++ diese nicht schneidet.
JD

6

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

Höhere Sprachen können dies sehr gut, indem sie den Zugriff auf viele effiziente vorgefertigte Datenstrukturen erleichtern und Praktiken fördern, mit denen Sie ineffizienten Code vermeiden können. Natürlich können sie es manchmal auch einfach machen, eine Menge wirklich langsamen Codes zu schreiben, sodass Sie Ihre Plattform immer noch kennen müssen.

Außerdem holt C ++ "neue" Funktionen (beachten Sie die Anführungszeichen) wie STL-Container, automatische Zeiger usw. ein - siehe beispielsweise die Boost-Bibliothek. Und gelegentlich stellen Sie möglicherweise fest, dass der schnellste Weg, um eine Aufgabe zu erledigen, eine Technik wie die Zeigerarithmetik erfordert, die in einer höheren Sprache verboten ist. In der Regel können Sie jedoch eine Bibliothek aufrufen, die in einer Sprache geschrieben ist, die sie wie gewünscht implementieren kann .

Die Hauptsache ist, die Sprache zu kennen, die Sie verwenden, die zugehörige API, was sie kann und welche Einschränkungen sie hat.


5

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


4

Hier ist ein weiterer interessanter Benchmark, den Sie selbst auf Ihrem eigenen Computer ausprobieren 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 sehr unterschiedlich ist, je nachdem, welcher Browser es ausführt. Gleiches 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. Daher wird die Geschwindigkeit nicht vom Hosting-Browser beeinflusst.


4

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

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

Und so weiter, es ist voreingenommen, ja;)

Mit C # und Java zahlen Sie einen Preis für das, was Sie erhalten (schnellere Codierung, automatische Speicherverwaltung, große Bibliothek usw.). Aber Sie haben nicht viel Raum, um über die Details zu feilschen: Nehmen Sie das komplette Paket oder nichts.

Selbst wenn diese Sprachen einen Code so optimieren können, dass er schneller als kompilierter Code ausgeführt wird, 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 sicher (extreme Knautschzone) und nachdem Sie einige Zeit Gas gegeben haben, ist es sogar so schnell wie ein Standardauto! Warum haben wir nicht alle einen LKW, 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 für gesammelten Müll, weil sie so wenig Müll erzeugt" Linktext


Nun, ich denke, er hat eine gute Vorstellung von den Nachteilen, er sagte auch: "C macht es einfach, sich in den Fuß zu schießen; C ++ macht es schwieriger, aber wenn Sie es tun, bläst es Ihr ganzes Bein ab";)
Frunsi

"Benötigen sie eine riesige installierte Bibliothek?" Java behebt dieses Problem mit Projektpuzzles, glaube ich.
toc777

"In C ++ bekommen Sie, wofür Sie bezahlen, nicht mehr und nicht weniger". Gegenbeispiel: Ich habe eine RB-Baumimplementierung in OCaml und C ++ (GNU GCC) verglichen, bei der eine Ausnahme verwendet wurde, um lange aus der Rekursion herauszuspringen, wenn bereits ein hinzugefügtes Element vorhanden war, um die vorhandene Menge wiederzuverwenden. OCaml war bis zu 6x schneller als C ++, da es sich nicht lohnt, nach Destruktoren zu suchen, da der Stapel abgewickelt wird.
JD

3
@ Jon: aber irgendwann (später?) Muss es die Objekte trotzdem zerstören (zumindest muss es seinen Speicher freigeben). Beachten Sie auch, dass Ausnahmen für Ausnahmefälle gelten, zumindest in C ++ sollte diese Regel eingehalten werden. C ++ - Ausnahmen können schwerwiegend sein, wenn Ausnahmen auftreten. Dies ist ein Kompromiss.
Frunsi

@ Jon: Vielleicht versuchen Sie, Ihren Benchmark mit timesauf einer Shell zu wiederholen . Damit wird das gesamte Programm überprüft, nicht nur ein einzelner Aspekt. Sind die Ergebnisse dann ähnlich?
Frunsi

3

Der von einem Java- oder C # -Compiler erzeugte ausführbare Code wird nicht interpretiert - er wird "just in time" (JIT) zu nativem Code kompiliert. Wenn also zum ersten Mal Code in einem Java / C # -Programm während der Ausführung auftritt, entsteht ein gewisser Overhead, da der "Laufzeit-Compiler" (auch bekannt als JIT-Compiler) den Bytecode (Java) oder IL-Code (C #) in native Maschinenanweisungen umwandelt. Wenn dieser Code jedoch das nächste Mal auftritt, während die Anwendung noch ausgeführt wird, wird der native Code sofort ausgeführt. Dies erklärt, wie einige Java / C # -Programme anfangs langsam erscheinen, dann aber eine bessere Leistung erzielen, je länger sie ausgeführt werden. Ein gutes Beispiel ist eine ASP.Net-Website. Beim ersten Zugriff auf die Website kann dies etwas langsamer sein, da der C # -Code vom JIT-Compiler zu nativem Code kompiliert wird.


3

Hier einige gute Antworten zu der spezifischen Frage, die Sie gestellt haben. Ich möchte zurücktreten und das Gesamtbild betrachten.

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

  • Manuelle Speicherverwaltung ist schwer korrekt durchzuführen (keine Lecks) und noch schwieriger effizient durchzuführen (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 Bereitstellung 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 korrekt funktioniert. Das bedeutet, dass ich meine Algorithmen optimieren kann, ohne dass das Risiko besteht, dass Fehler auftreten (und Benutzer mögen keine Software, die abstürzt, selbst wenn dies schnell geschieht!).

  • 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 # zu schreiben als in C ++, daher bin ich eher in der Lage, die Arbeit in den Hintergrund zu rücken, während die Benutzeroberfläche reagiert, oder eine Fortschritts- oder Hearbeat-Benutzeroberfläche bereitzustellen, wenn das Programm für eine Weile blockiert werden muss. Dies macht nichts schneller, aber es macht Benutzer glücklicher über das Warten.

Alles, was ich über C # gesagt habe, gilt wahrscheinlich für Java. Ich habe einfach nicht die Erfahrung, dies mit Sicherheit zu sagen.


3

Wenn Sie ein Java / C # -Programmierer sind, der C ++ lernt, werden Sie versucht sein, weiter in Java / C # zu denken und wörtlich in die C ++ - Syntax zu übersetzen. In diesem Fall erhalten Sie nur die zuvor genannten Vorteile von nativem Code gegenüber interpretiertem / JIT. Um den größten Leistungsgewinn in C ++ im Vergleich zu 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 Muttersprache] verstümmelt den Geist bis zur Genesung.
Um Jeff Atwood zu paraphrasieren : Sie können [Ihre Muttersprache] in jeder neuen Sprache schreiben.


1
Ich vermute, dass das Sprichwort "Sie können FORTRAN in jeder Sprache schreiben" vor Jeffs Karriere liegt.
David Thornley

3

Eine der wichtigsten JIT-Optimierungen ist das Inlining von Methoden. Java kann sogar virtuelle Methoden einbinden, wenn es die Laufzeitkorrektheit gewährleisten kann. Diese Art der Optimierung kann normalerweise nicht von statischen Standard-Compilern durchgeführt werden, da eine Analyse des gesamten Programms erforderlich ist, was aufgrund der separaten Kompilierung schwierig ist (im Gegensatz dazu verfügt JIT über das gesamte Programm). Das Inlining von Methoden verbessert andere Optimierungen und bietet größere Codeblöcke zur Optimierung.

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


Beachten Sie, dass freeund deleteauch nicht deterministisch sind und GC durch Nichtzuweisung deterministisch gemacht werden kann.
JD

3

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

1 / Die Java-Laufzeitumgebung ist normalerweise in der Lage, häufig ausgeführte Codeteile zu erkennen und eine Just-in-Time-Kompilierung (JIT) dieser Abschnitte durchzuführen, damit sie in Zukunft mit der vollen kompilierten Geschwindigkeit ausgeführt werden.

2 / Große Teile der Java-Bibliotheken werden kompiliert, sodass Sie beim Aufrufen einer Bibliotheksfunktion kompilierten Code ausführen, der nicht interpretiert wird. Sie können den Code (in C) sehen, indem Sie das OpenJDK herunterladen.

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

4 / Da ein Großteil der Validierung des Java-Bytecodes 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.


1
Zu Punkt 2, "2 / Große Teile der Java-Bibliotheken werden so kompiliert, dass Sie beim Aufrufen einer Bibliotheksfunktion kompilierten Code ausführen, der nicht interpretiert wird": Haben Sie ein Zitat dafür? Wenn es wirklich so wäre, wie Sie es beschreiben, würde ich erwarten, dass mein Debugger häufig auf nativen Code stößt, aber das tue ich nicht.
Cero

Re: cero-Debugger verwenden häufig weniger effiziente, aber ausdrucksstärkere Pfade und sind daher kein guter Indikator für leistungsbezogene Aspekte.
Guvante

2
Diese HUGH-Bibliothek bietet einen weiteren enormen Leistungsgewinn: Bibliothekscode ist wahrscheinlich besser geschrieben als das, was viele Programmierer selbst schreiben (aufgrund einer begrenzten Zeit und mangelnder Fachkenntnisse) und auf Java, und zwar aus vielen Gründen, die Programmierer häufig verwenden die Bibliothek.
Liran Orevi

3

Orion Adrian , lassen Sie mich Ihren Beitrag umkehren , um zu sehen, wie unbegründet Ihre Bemerkungen sind, denn auch über C ++ kann viel gesagt werden. Und wenn Sie sagen, dass der Java / C # -Compiler leere Funktionen optimiert, klingen Sie wirklich so, als wären Sie nicht mein Experte für Optimierung, denn a) warum sollte ein echtes Programm leere Funktionen enthalten, außer wirklich schlechtem Legacy-Code, b) das ist wirklich nicht so Schwarz- und Blutungskantenoptimierung.

Abgesehen von diesem Satz haben Sie offen über Zeiger geschimpft, aber funktionieren Objekte in Java und C # nicht im Grunde wie C ++ - Zeiger? Dürfen sie sich nicht überschneiden? Dürfen sie nicht null sein? C (und die meisten C ++ - Implementierungen) hat das Schlüsselwort Restrict, beide haben Werttypen, C ++ hat einen Verweis 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 Bereitstellung ein für alle Mal auf Ihrem High-Memory-Server mit vielen Kern-Build-Servern kompiliert - Optimierungen vornehmen kann, die ein C # -kompiliertes Programm ermöglicht kann nicht, weil es eine Menge Zeit dafür hat. Der Compiler kann feststellen, ob es sich bei dem Computer um Intel oder AMD handelt. Pentium 4, Core Solo oder Core Duo; oder wenn SSE4 usw. unterstützt wird und Ihr Compiler den Laufzeitversand nicht unterstützt, können Sie dies selbst lösen, indem Sie eine Handvoll spezialisierter Binärdateien bereitstellen.

Das AC # -Programm wird normalerweise beim Ausführen so kompiliert, dass es auf allen Computern ordnungsgemäß ausgeführt wird. Es ist jedoch nicht so stark optimiert, wie es für eine einzelne Konfiguration (z. B. Prozessor, Befehlssatz, andere Hardware) möglich ist, und es muss einige Zeit in Anspruch nehmen zuerst. Funktionen wie Schleifenspaltung, Schleifeninversion, automatische Vektorisierung, Optimierung des gesamten Programms, Vorlagenerweiterung, Börsengang und vieles mehr sind nur schwer und vollständig auf eine Weise zu lösen, die den Endbenutzer nicht stört.

Zusätzlich ermöglichen 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 Programmablauf haben, gibt es viele Optimierungen, die einfach nicht sicher sind.

Außerdem führen C ++ und C viele Stapelzuweisungen gleichzeitig mit nur einer Registerinkrementierung durch, was sicherlich effizienter ist als die Zuordnungen von Javas und C # für die Abstraktionsebene zwischen dem Garbage Collector und Ihrem Code.

Jetzt kann ich in diesem nächsten Punkt nicht für Java sprechen, aber ich weiß, dass C ++ - Compiler beispielsweise tatsächlich Methoden und Methodenaufrufe entfernen, wenn sie wissen, dass der Hauptteil der Methode leer ist, häufige Unterausdrücke eliminieren und möglicherweise versuchen, es erneut zu versuchen Um eine optimale Registernutzung zu finden, erzwingt es keine Überprüfung der Grenzen, es automatisiert Schleifen und innere Schleifen automatisch und invertiert innere nach äußere, es verschiebt Bedingungen aus Schleifen heraus, es teilt und trennt Schleifen. Es wird std :: vector in native Null-Overhead-Arrays erweitern, wie Sie es auf C-Weise tun würden. Es werden interprozedurale Optimierungen durchgeführt. Es werden Rückgabewerte direkt am Aufruferstandort erstellt. Es wird Ausdrücke falten und verbreiten. Die Daten werden cachefreundlich neu angeordnet. Es wird Jump Threading machen. Sie können damit Raytracer zur Kompilierungszeit ohne Laufzeitaufwand schreiben. Es werden sehr teure graphbasierte Optimierungen vorgenommen. Es wird die Stärke reduzieren, wenn es bestimmte Codes durch syntaktisch völlig ungleichen, aber semantisch äquivalenten Code ersetzt (das alte "xor foo, foo" ist nur die einfachste, wenn auch veraltete Optimierung dieser Art). Wenn Sie es freundlich fragen, können Sie IEEE-Gleitkommastandards weglassen und noch mehr Optimierungen wie die Neuordnung von Gleitkommaoperanden aktivieren. Nachdem Ihr Code massiert und massakriert wurde, wird möglicherweise der gesamte Vorgang wiederholt, da häufig bestimmte Optimierungen die Grundlage für noch sicherere Optimierungen bilden. Es kann auch sein, dass Sie es erneut mit gemischten Parametern versuchen und sehen, wie die andere Variante in ihrem internen Ranking punktet. Und es wird diese Art von Logik in Ihrem gesamten Code verwenden. Wenn es bestimmte Codes durch syntaktisch völlig ungleichen, aber semantisch äquivalenten Code ersetzt (das alte "xor foo, foo" ist nur die einfachste, wenn auch veraltete Optimierung dieser Art). Wenn Sie es freundlich fragen, können Sie IEEE-Gleitkommastandards weglassen und noch mehr Optimierungen wie die Neuordnung von Gleitkommaoperanden aktivieren. Nachdem Ihr Code massiert und massakriert wurde, wird möglicherweise der gesamte Vorgang wiederholt, da häufig bestimmte Optimierungen die Grundlage für noch sicherere Optimierungen bilden. Es kann auch sein, dass Sie es erneut mit gemischten Parametern versuchen und sehen, wie die andere Variante in ihrem internen Ranking punktet. Und es wird diese Art von Logik in Ihrem gesamten Code verwenden. Wenn es bestimmte Codes durch syntaktisch völlig ungleichen, aber semantisch äquivalenten Code ersetzt (das alte "xor foo, foo" ist nur die einfachste, wenn auch veraltete Optimierung dieser Art). Wenn Sie es freundlich fragen, können Sie IEEE-Gleitkommastandards weglassen und noch mehr Optimierungen wie die Neuordnung von Gleitkommaoperanden aktivieren. Nachdem Ihr Code massiert und massakriert wurde, wird möglicherweise der gesamte Vorgang wiederholt, da häufig bestimmte Optimierungen die Grundlage für noch sicherere Optimierungen bilden. Es kann auch sein, dass Sie es erneut mit gemischten Parametern versuchen und sehen, wie die andere Variante in ihrem internen Ranking punktet. Und es wird diese Art von Logik in Ihrem gesamten Code verwenden. Wenn Sie es freundlich fragen, können Sie IEEE-Gleitkommastandards weglassen und noch mehr Optimierungen wie die Neuordnung von Gleitkommaoperanden aktivieren. Nachdem Ihr Code massiert und massakriert wurde, wird möglicherweise der gesamte Vorgang wiederholt, da häufig bestimmte Optimierungen die Grundlage für noch sicherere Optimierungen bilden. Es kann auch sein, dass Sie es erneut mit gemischten Parametern versuchen und sehen, wie die andere Variante in ihrem internen Ranking punktet. Und es wird diese Art von Logik in Ihrem gesamten Code verwenden. Wenn Sie es freundlich fragen, können Sie IEEE-Gleitkommastandards weglassen und noch mehr Optimierungen wie die Neuordnung von Gleitkommaoperanden aktivieren. Nachdem Ihr Code massiert und massakriert wurde, wird möglicherweise der gesamte Vorgang wiederholt, da häufig bestimmte Optimierungen die Grundlage für noch sicherere Optimierungen bilden. Es kann auch sein, dass Sie es erneut mit gemischten Parametern versuchen und sehen, wie die andere Variante in ihrem internen Ranking punktet. Und es wird diese Art von Logik in Ihrem gesamten Code verwenden. Möglicherweise wird es auch nur mit gemischten Parametern wiederholt, um zu sehen, wie die andere Variante in ihrem internen Ranking punktet. Und es wird diese Art von Logik in Ihrem gesamten Code verwenden. Möglicherweise wird es auch nur mit gemischten Parametern wiederholt, um zu sehen, wie die andere Variante in ihrem internen Ranking punktet. Und es wird diese Art von Logik in Ihrem gesamten Code verwenden.

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

Nachdem dies alles gesagt ist, können in C ++ viele Optimierungen vorgenommen werden, die alles wegblasen, was Sie mit C # tun können, insbesondere im Bereich der Zahlenkalkulation, Echtzeit und Metallnähe, aber nicht ausschließlich dort. Sie müssen nicht einmal einen einzigen Zeiger berühren, um einen langen Weg zurückzulegen.

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 möglicherweise cool, klingen aber im Allgemeinen nicht mit Sicherheit glaubwürdig.

Wie auch immer, um Frieden zu schließen: AOT ist großartig, genau wie JIT . Die einzig richtige Antwort kann sein: Es kommt darauf an. Und die wirklich klugen Leute wissen, dass man sowieso das Beste aus beiden Welten nutzen kann.


2

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 von Ihnen geschriebenen C ++ - Code generiert, bis zu dem Punkt, an dem der C ++ - Code langsamer als Java ist und die Interpretationskosten.

Die Wahrscheinlichkeit, dass dies tatsächlich geschieht, ist jedoch ziemlich gering - es sei denn, Java verfügt möglicherweise über eine sehr gut geschriebene Bibliothek und Sie haben Ihre eigene schlecht geschriebene C ++ - Bibliothek.


Ich glaube auch, dass es auch ein bestimmtes Sprachgewicht gibt, wenn Sie auf einer niedrigeren Ebene mit weniger Abstraktion arbeiten, werden Sie ein Programm entwickeln, das schneller ist. Dies hat nichts mit den Punkten über die Bytecode-Ausführung selbst zu tun.
Brian R. Bondy

2

Tatsächlich läuft C # nicht wirklich in einer virtuellen Maschine wie Java. IL wird in Assemblersprache kompiliert, die vollständig nativer Code ist und mit der gleichen Geschwindigkeit wie nativer Code ausgeführt wird. Sie können eine .NET-Anwendung vorab JITEN, wodurch die JIT-Kosten vollständig entfallen, und dann führen Sie vollständig nativen Code aus.

Die Verlangsamung mit .NET ist nicht darauf zurückzuführen, dass .NET-Code langsamer ist, sondern darauf, dass hinter den Kulissen viel mehr getan wird, um beispielsweise Müll zu sammeln, Referenzen zu überprüfen, vollständige Stapelrahmen zu speichern usw. Dies kann sehr leistungsfähig und hilfreich sein, wenn Erstellen von Anwendungen, aber auch mit Kosten verbunden. 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 geschrieben haben, erhalten Sie wahrscheinlich ein viel langsameres Programm, da die .NET-Laufzeit optimiert und genau abgestimmt wurde.

Eine der Stärken von verwaltetem Code ist jedoch, dass er vollständig überprüfbar ist, d. H. Sie können überprüfen, ob der Code niemals auf den Speicher eines anderen Prozesses zugreift oder unsage Dinge ausführt, bevor Sie ihn ausführen. Microsoft hat einen Forschungsprototyp eines vollständig verwalteten Betriebssystems, der überraschenderweise gezeigt hat, dass eine zu 100% verwaltete Umgebung tatsächlich eine erheblich schnellere Leistung als jedes moderne Betriebssystem erbringen 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 Folge, die über dieses Projekt spricht.


1

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 einzigen Durchgang freizugeben, wobei die meisten C / C ++ - Heap-Objekte einzeln freigegeben werden. eine Zeit.

Aus Wikipedia :

Für viele praktische Zwecke können Zuweisungs- / Freigabe-intensive Algorithmen, die in Garbage-Collected-Sprachen implementiert sind, bei manueller Heap-Zuweisung tatsächlich schneller sein als ihre Entsprechungen. Ein Hauptgrund dafür ist, dass der Garbage Collector es dem Laufzeitsystem ermöglicht, Zuordnungs- und Freigabevorgänge auf potenziell vorteilhafte Weise zu amortisieren.

Trotzdem habe ich viel C # und viel C ++ geschrieben und viele Benchmarks durchgeführt. Nach meiner Erfahrung ist C ++ viel schneller als C #, auf zwei Arten: (1) , wenn Sie einen Code nehmen , dass Sie in C # geschrieben haben, Portierung auf C ++ der nativen Code neigt dazu , schneller zu 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 Speicherbereinigung eine verwaltete Anwendung massiv verlangsamen. Die .NET CLR leistet schreckliche Arbeit mit großen Haufen (z. B.> 2 GB) und kann viel Zeit in GC verbringen - selbst in Anwendungen, in denen nur wenige oder gar keine Objekte mit mittlerer Lebensdauer vorhanden sind.

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


1
Das Problem ist, dass bei lang laufenden Prozessen wie einem Webserver Ihr Speicher im Laufe der Zeit so fragmentiert wird (in einem von C ++ geschriebenen Programm), dass Sie etwas implementieren müssen, das der Speicherbereinigung ähnelt (oder von Zeit zu Zeit neu starten müssen, siehe IIS) ).
Tony BenBrahim

3
Ich habe das bei den großen Unix-Programmen, die für immer laufen sollen, nicht beobachtet. Sie sind in der Regel in C geschrieben, was für die Speicherverwaltung noch schlechter ist als in C ++.
David Thornley

Die Frage ist natürlich, ob wir eine Implementierung eines Programms in verwaltetem mit nicht verwaltetem Code oder die theoretische Spitzenleistung der Sprache vergleichen. Natürlich kann nicht verwalteter Code immer mindestens so schnell sein wie verwaltet, da Sie im schlimmsten Fall einfach ein nicht verwaltetes Programm schreiben können, das genau das Gleiche tut wie der verwaltete Code! Die meisten Leistungsprobleme sind jedoch algorithmisch und nicht mikro. Außerdem optimieren Sie verwalteten und nicht verwalteten Code nicht auf die gleiche Weise, sodass "C ++ in C #" normalerweise nicht gut funktioniert.
Kyoryu

2
In C / C ++ Sie können kurzlebige Objekte auf dem Stapel zuweisen, und Sie tun , wenn seine angemessen. In verwaltetem Code können Sie keine Wahl haben. Auch in C / C ++ Sie können Listen von Objekten in contigous Bereichen zuordnen (neu Foo [100]), in verwaltetem Code kann man nicht. Ihr Vergleich ist also nicht gültig. Nun, diese Entscheidungsfreiheit belastet die Entwickler, aber auf diese Weise lernen sie die Welt kennen, in der sie leben (Erinnerung ......).
Frunsi

@frunsi: "In C / C ++ können Sie Listen von Objekten in zusammenhängenden Bereichen zuordnen (neues Foo [100]), in verwaltetem Code nicht". Das ist falsch. Lokale Werttypen werden stapelweise zugewiesen, und Sie können sogar Arrays davon in C # stapelweise zuordnen. Es gibt sogar in C # geschriebene Produktionssysteme, die im eingeschwungenen Zustand völlig zuordnungslos sind.
JD


1

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


1

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

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

Es kommt oft darauf an:

  • Programme haben Hotspots. Selbst wenn Sie 95% des auszuführenden Codes langsamer ausführen, können Sie dennoch wettbewerbsfähig sein, wenn Sie bei den heißen 5% schneller 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 sogar noch schneller).

  • Ein JIT-Compiler verfügt über viele Informationen, die ein statischer Compiler nicht hat (wie die tatsächlichen Daten, die Sie diesmal haben).

  • Ein JIT-Compiler kann zur Laufzeit Optimierungen vornehmen, die herkömmliche Linker nicht wirklich ausführen dürfen (z. B. das Neuordnen von Zweigen, sodass der allgemeine Fall flach ist, oder das Inlining von Bibliotheksaufrufen).

Alles in allem sind C / C ++ für die Leistung ziemlich miese Sprachen: Es gibt relativ wenig Informationen zu Ihren Datentypen, keine Informationen zu Ihren Daten und keine dynamische Laufzeit, um die Laufzeitoptimierung zu verbessern.


1

Es kann zu kurzen Bursts kommen, wenn Java oder CLR schneller als C ++ sind, aber insgesamt ist die Leistung für die Lebensdauer der Anwendung schlechter: Einige Ergebnisse hierzu finden Sie unter www.codeproject.com/KB/dotnet/RuntimePerformance.aspx.



1

Nach meinem Verständnis erzeugt C / C ++ nativen Code, der auf einer bestimmten Maschinenarchitektur ausgeführt werden kann. Umgekehrt laufen Sprachen wie Java und C # auf einer virtuellen Maschine, die die native Architektur abstrahiert. Logischerweise scheint es Java oder C # aufgrund dieses Zwischenschritts unmöglich zu sein, die Geschwindigkeit von C ++ zu erreichen. Mir wurde jedoch gesagt, dass die neuesten Compiler ("Hot Spot") diese Geschwindigkeit erreichen oder sogar überschreiten können.

Das ist unlogisch. Die Verwendung einer Zwischendarstellung beeinträchtigt die Leistung nicht von Natur aus. Zum Beispiel kompiliert llvm-gcc C und C ++ über LLVM IR (eine virtuelle Maschine mit unendlichen Registern) zu nativem Code und erzielt eine hervorragende Leistung (oft besser als GCC).

Vielleicht ist dies eher eine Compiler-Frage als eine Sprachfrage, aber kann jemand im Klartext erklären, wie eine dieser Sprachen der virtuellen Maschine eine bessere Leistung als eine Muttersprache erzielen kann?

Hier sind einige Beispiele:

  • Virtuelle Maschinen mit JIT-Kompilierung erleichtern die Generierung von Laufzeitcode (z. B. System.Reflection.Emitin .NET), sodass Sie generierten Code im laufenden Betrieb in Sprachen wie C # und F # kompilieren können, müssen jedoch einen vergleichsweise langsamen Interpreter in C oder C ++ schreiben. Zum Beispiel, um reguläre Ausdrücke zu implementieren.

  • Teile der virtuellen Maschine (z. B. die Schreibbarriere und der Allokator) 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.

  • Die dynamische Verknüpfung von nativem Code erfordert die Konformität mit einem ABI, der die Leistung beeinträchtigen und die Optimierung des gesamten Programms verhindern kann, während die Verknüpfung normalerweise auf VMs verzögert wird und von Optimierungen des gesamten Programms (wie den reifizierten Generika von .NET) profitieren kann.

Ich möchte auch einige Probleme mit der oben hoch bewerteten Antwort von paercebal ansprechen (weil immer wieder jemand meine Kommentare zu seiner Antwort löscht), die eine kontraproduktiv polarisierte Sichtweise darstellen:

Die Codeverarbeitung erfolgt zur Kompilierungszeit ...

Daher funktioniert die Metaprogrammierung von Vorlagen nur, wenn das Programm zur Kompilierungszeit verfügbar ist, was häufig nicht der Fall ist, z. B. ist es unmöglich, eine wettbewerbsfähig performante Bibliothek für reguläre Ausdrücke in Vanilla C ++ zu schreiben, da sie nicht in der Lage ist, Laufzeitcode zu generieren (ein wichtiger Aspekt von 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 zur Kompilierungszeit bekannt sind.

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

Unabhängig von der JIT-Optimierung ist nichts so schnell wie der direkte Zeigerzugriff auf den Speicher. Wenn Sie zusammenhängende Daten im Speicher haben, wird der Zugriff über C ++ - Zeiger (dh C-Zeiger ... Geben wir Caesar die Schuld) schneller als in Java / C #.

Die Leute haben beobachtet, dass Java beim SOR-Test aus dem SciMark2-Benchmark C ++ schlägt, gerade weil Zeiger aliasingbezogene Optimierungen behindern.

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


0

Zusätzlich zu dem, was einige andere gesagt haben, sind .NET und Java meines Wissens besser in der Speicherzuweisung. Zum Beispiel können sie Speicher komprimieren, wenn er fragmentiert wird, während C ++ dies nicht kann (nativ, aber es kann, wenn Sie einen cleveren Garbage Collector verwenden).


Oder wenn Sie einen besseren C ++ - Allokator und / oder einen besseren Objektpool verwenden. Dies ist aus C ++ - Sicht alles andere als magisch und kann dazu führen, dass die "Heap-Zuweisung" zu einer so schnellen Stapelzuweisung wird.
Paercebal

Wenn Sie immer alles auf dem Heap zuweisen, sind .NET und Java möglicherweise sogar leistungsfähiger als C / C ++. Aber Sie werden dies in C / C ++ einfach nicht tun.
Frunsi

0

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

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

Der Vorteil von C ++ ist jedoch, dass Sie sich selbst optimieren können, da Sie sonst nicht mehr mit dem arbeiten können, was der Compiler / jvm tut. Wenn Sie Ihre eigenen Container erstellen, Ihre eigene Speicherverwaltung schreiben, die ausgerichtet ist, SIMD verwenden und hier und da zur Assembly wechseln, können Sie mindestens das 2- bis 4-fache der Leistung der meisten C ++ - Compiler selbst beschleunigen. Für einige Operationen 16x-32x. Das bedeutet, dass dieselben Algorithmen verwendet werden. Wenn Sie bessere Algorithmen verwenden und parallelisieren, können die Erhöhungen dramatisch sein, manchmal tausende Male schneller als bei häufig verwendeten Methoden.


0

Ich betrachte es aus verschiedenen Blickwinkeln.

  1. Wird verwalteter oder nicht verwalteter Code bei unendlicher Zeit und Ressourcen schneller sein? Die Antwort lautet eindeutig, dass nicht verwalteter Code in diesem Aspekt 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 direkt in eine andere übersetzen, wie viel schlechter wird es dann sein? Wahrscheinlich viel für zwei beliebige Sprachen. Die meisten Sprachen erfordern unterschiedliche Optimierungen und haben unterschiedliche Fallstricke. Bei der Mikroleistung geht es oft darum, diese Details zu kennen.
  3. Welche von zwei Sprachen wird bei begrenzter Zeit und begrenzten Ressourcen ein besseres Ergebnis erzielen? Dies ist die interessanteste Frage, da eine verwaltete Sprache möglicherweise etwas langsamer Code erzeugt (vorausgesetzt, ein Programm ist für diese Sprache angemessen geschrieben), diese Version jedoch wahrscheinlich früher erstellt wird, sodass mehr Zeit für die Optimierung aufgewendet wird.

0

Eine sehr kurze Antwort: Mit einem festen Budget erzielen Sie eine leistungsstärkere Java-Anwendung als eine C ++ - Anwendung (ROI-Überlegungen). Darüber hinaus verfügt die Java-Plattform über anständigere Profiler, mit denen Sie Ihre Hotspots schneller lokalisieren können

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.