Wie viel schneller ist C ++ als C #?


245

Oder ist es jetzt umgekehrt?

Soweit ich gehört habe, gibt es einige Bereiche, in denen sich C # als schneller als C ++ erweist, aber ich hatte nie den Mut, es selbst zu testen.

Ich dachte, jeder von Ihnen könnte diese Unterschiede im Detail erklären oder mich an die richtige Stelle für Informationen dazu verweisen.


7
Geschützt, um zu verhindern, dass weitere zufällige Benchmarks veröffentlicht werden. Wenn Sie glauben, dass Sie Ihren Fall vertreten können, benötigen Sie 10 Wiederholungen, um dies zu tun.
Robert Harvey

2
Wie ist das überhaupt nicht als Meinung / Argumentation abgeschlossen? Bin ich nicht immer noch auf StackOverflow? (Nicht naheliegend, nur neugierig. Ich liebe Fragen, die zu Meinungsargumenten führen)
Bill K

1
Es ist fast eine strittige Frage, da wir in einem Zeitalter leben, in dem IL in CPP konvertiert und von dort aus optimiert werden kann: docs.unity3d.com/Manual/IL2CPP.html
pixelpax

Eine Sprache, die nach einem Array-Zugriff außerhalb des Bereichs sucht, übertrifft niemals eine Sprache, die dies nicht tut.
Seva Alekseyev

@SevaAlekseyev Es ist nicht die Sprache, die dies tut, sondern der Compiler. Einer der Gründe, warum C ++ so schnell ist (abgesehen von den offensichtlichen), ist, dass es C ++ - Compiler seit 35 Jahren gibt (wenn nicht mehr). Nichts hindert C # -Compiler daran, mit der Zeit besser zu werden. Für den Fall, den Sie erwähnen, lesen Sie bitte diesen stackoverflow.com/questions/16713076/…
Trap

Antworten:


342

Es gibt keinen strengen Grund, warum eine Bytecode-basierte Sprache wie C # oder Java mit einer JIT nicht so schnell sein kann wie C ++ - Code. C ++ - Code war jedoch lange Zeit deutlich schneller und ist es auch heute noch in vielen Fällen. Dies ist hauptsächlich darauf zurückzuführen, dass die Implementierung fortgeschrittener JIT-Optimierungen kompliziert ist und die wirklich coolen erst jetzt eintreffen.

Daher ist C ++ in vielen Fällen schneller. Dies ist jedoch nur ein Teil der Antwort. Die Fälle, in denen C ++ tatsächlich schneller ist, sind hochoptimierte Programme, in denen erfahrene Programmierer den Code gründlich optimiert haben. Dies ist nicht nur sehr zeitaufwändig (und damit teuer), sondern führt auch häufig zu Fehlern aufgrund von Überoptimierungen.

Andererseits wird Code in interpretierten Sprachen in späteren Versionen der Laufzeit (.NET CLR oder Java VM) schneller, ohne dass Sie etwas tun müssen. Und es gibt viele nützliche Optimierungen, die JIT-Compiler durchführen können und die in Sprachen mit Zeigern einfach unmöglich sind. Einige argumentieren auch, dass die Speicherbereinigung im Allgemeinen genauso schnell oder schneller sein sollte wie die manuelle Speicherverwaltung, und in vielen Fällen ist dies auch der Fall. Sie können all dies im Allgemeinen in C ++ oder C implementieren und erreichen, aber es wird viel komplizierter und fehleranfälliger.

Wie Donald Knuth sagte, "ist vorzeitige Optimierung die Wurzel allen Übels". Wenn Sie wirklich sicher sind, dass Ihre Anwendung hauptsächlich aus einer sehr leistungskritischen Arithmetik besteht und dass dies der Engpass ist und in C ++ sicherlich schneller wird und Sie sicher sind, dass C ++ nicht mit Ihrer anderen in Konflikt steht Anforderungen, wählen Sie C ++. In jedem anderen Fall sollten Sie sich darauf konzentrieren, Ihre Anwendung zuerst in der für Sie am besten geeigneten Sprache korrekt zu implementieren, dann Leistungsengpässe zu finden, wenn sie zu langsam ausgeführt wird, und dann darüber nachzudenken, wie Sie den Code optimieren können. Im schlimmsten Fall müssen Sie möglicherweise C-Code über eine fremde Funktionsschnittstelle aufrufen, damit Sie weiterhin wichtige Teile in einer niedrigeren Sprache schreiben können.

Denken Sie daran, dass es relativ einfach ist, ein korrektes Programm zu optimieren, aber viel schwieriger, ein optimiertes Programm zu korrigieren.

Es ist unmöglich, tatsächliche Prozentsätze der Geschwindigkeitsvorteile anzugeben, dies hängt weitgehend von Ihrem Code ab. In vielen Fällen ist die Implementierung der Programmiersprache nicht einmal der Engpass. Nehmen Sie die Benchmarks unter http://benchmarksgame.alioth.debian.org/ mit großer Skepsis, da diese weitgehend arithmetischen Code testen, der Ihrem Code höchstwahrscheinlich überhaupt nicht ähnlich ist.


92
<quote> Code in interpretierten Sprachen wird in späteren Versionen der Laufzeit schneller. </ quote> Da Code, der von einer besseren Version des Compilers kompiliert wurde, auch schneller wird.
Martin York

47
Tatsächlich gibt es mindestens einen Grund: JIT muss schnell sein und kann es sich nicht leisten, Zeit mit verschiedenen erweiterten Optimierungen zu verbringen, die einem C ++ - Compiler zur Verfügung stehen.
Nemanja Trifunovic

63
"führt aber auch häufig zu Fehlern aufgrund von Überoptimierungen." [Zitat dringend benötigt]. Ich arbeite in einem nationalen Labor und wir optimieren unseren Code. Dies führt normalerweise nicht zu fehlerhaftem Code.
Todd Gamblin

35
"Es ist relativ einfach, ein korrektes Programm zu optimieren, aber viel schwieriger, ein optimiertes Programm zu korrigieren."
Gradbot

20
Inge: Ich bin mir nicht sicher, ob Sie dort auf dem richtigen Weg sind. Ja, C # ist in einer anderen Sprache implementiert, aber der JIT-Compiler generiert Maschinencode, sodass es sich nicht um eine interpretierte Sprache handelt. Somit ist es nicht durch seine C ++ - Implementierung beschränkt. Ich bin mir nicht sicher, warum Sie denken, dass das Hinzufügen eines Managers zu etwas von Natur aus schneller geht.
Martin Probst

202

C # ist vielleicht nicht schneller, aber es macht SIE / MICH schneller. Das ist die wichtigste Maßnahme für das, was ich tue. :) :)


68
Haha, es gibt ein gutes Zitat von Larry Wall zu diesem Thema. Er spricht über Perl, aber es kann bei allen Diskussionen über Sprachen und Leistung berücksichtigt werden: "Frühere Computersprachen wie Fortran und C wurden entwickelt, um teure Computerhardware effizient zu nutzen. Im Gegensatz dazu wurde Perl entwickelt teure Computerprogrammierer effizient nutzen "
Falaina

60
1. "C # ist viel schneller als C ++" 2. "Es kann nicht wahr sein" 1. "Sicher kann es" 2. "Um wie viel?" 1. "Normalerweise um 3-4 Monate"
Dmitry S.

2
Für C ++, das wirklich von den Bibliotheken abhängt, die Sie verwenden, ist C # normalerweise nicht schneller, .NET ist, wenn Sie über Produktivität sprechen
Ion Todirel

Es ist der gleiche Grund, warum Sie Python anstelle von C verwenden könnten, um Code zu schreiben ... aber nachdem Sie einige umfangreiche Berechnungen erstellt haben, können Sie den Unterschied in der Leistung spüren.
Ch3shire

Das hängt davon ab, was Sie gewohnt sind. Ich programmiere in C ++ viel schneller als in C #. Bibliothekskenntnisse machen einen großen Teil davon aus, da Sie das Rad für grundlegende Aufgaben nicht neu erfinden möchten. Das Hauptproblem von C / C ++ war die Zeigerverwaltung, die mit intelligenten Zeigern so gut wie gelöst wird. Allerdings fehlt C ++ Serious eine umfangreiche Bibliothek, wie sie .NET und Java bieten, und dies kann die Entwicklung erheblich beschleunigen. Dies wird nicht bald gelöst sein, da diese Standard-Jungs ihre Zeit gerne mit Vorlagenverbesserungen anstelle von Bibliothekserweiterungen verbringen.
gast128

87

Es ist fünf Orangen schneller. Oder besser gesagt: Es kann keine (richtige) pauschale Antwort geben. C ++ ist eine statisch kompilierte Sprache (aber es gibt auch eine profilgesteuerte Optimierung). C # wird mithilfe eines JIT-Compilers ausgeführt. Es gibt so viele Unterschiede, dass Fragen wie „wie viel schneller“ nicht beantwortet werden können, auch nicht mit Größenordnungen.


177
Haben Sie Beweise für Ihre empörende Behauptung über fünf Orangen? Meine Experimente deuten alle auf höchstens 2 Orangen hin, mit einer Verbesserung von 3 Mangos bei der Metaprogrammierung von Vorlagen.
Alex

42
Bei Hefe klemmt er nicht, es sind Vorspeisen der Größenordnung schneller.
Chris

11
Nach meiner Erfahrung sind es eher 5,2 Orangen. Dies hängt jedoch von dem verwendeten Frucht-O-Meter ab.
Dio F

4
Update, StackOverflow selbst vermasselt und behandelt Kommentare ineffizient, also weniger Bananen (300 Bananen schlimmer als es sein sollte): meta.stackexchange.com/questions/254534/…
KeksArmee

87

Ich werde damit beginnen, einem Teil der akzeptierten (und gut bewerteten) Antwort auf diese Frage nicht zuzustimmen, indem ich sage:

Es gibt tatsächlich viele Gründe, warum JITted-Code langsamer ausgeführt wird als ein ordnungsgemäß optimiertes C ++ - Programm (oder eine andere Sprache ohne Laufzeit-Overhead), darunter:

  • Rechenzyklen, die zur Laufzeit für JITting-Code aufgewendet werden, sind per Definition für die Verwendung bei der Programmausführung nicht verfügbar.

  • Alle Hot Paths im JITter konkurrieren mit Ihrem Code um Anweisungen und Datencache in der CPU. Wir wissen, dass der Cache die Leistung dominiert und Muttersprachen wie C ++ per Definition diese Art von Konflikten nicht haben.

  • Das Zeitbudget eines Laufzeitoptimierers ist notwendigerweise viel eingeschränkter als das eines Optimierers zur Kompilierungszeit (wie ein anderer Kommentator hervorhob).

Fazit: Letztendlich können Sie mit ziemlicher Sicherheit eine schnellere Implementierung in C ++ erstellen als in C # .

Nun, wie viel schneller wirklich ist, ist nicht quantifizierbar, da es zu viele Variablen gibt: Aufgabe, Problemdomäne, Hardware, Qualität der Implementierungen und viele andere Faktoren. Sie haben Tests für Ihr Szenario durchgeführt, um den Leistungsunterschied festzustellen und dann zu entscheiden, ob sich der zusätzliche Aufwand und die Komplexität lohnen.

Dies ist ein sehr langes und komplexes Thema, aber der Vollständigkeit halber sollte erwähnt werden, dass das Laufzeitoptimierungsprogramm von C # hervorragend ist und bestimmte dynamische Optimierungen zur Laufzeit durchführen kann, die C ++ mit seiner Kompilierungszeit einfach nicht zur Verfügung stehen ( statischer) Optimierer. Trotzdem liegt der Vorteil in der Regel immer noch tief im Gericht der nativen Anwendung, aber der dynamische Optimierer ist der Grund für das oben angegebene Qualifikationsmerkmal "mit ziemlicher Sicherheit".

- -

In Bezug auf die relative Leistung war ich auch beunruhigt über die Zahlen und Diskussionen, die ich in einigen anderen Antworten gesehen habe. Ich dachte, ich würde mich einschalten und gleichzeitig die Aussagen unterstützen, die ich oben gemacht habe.

Ein großer Teil des Problems mit diesen Benchmarks besteht darin, dass Sie keinen C ++ - Code schreiben können, als ob Sie C # schreiben würden, und repräsentative Ergebnisse erwarten würden (z. B. wenn Sie Tausende von Speicherzuweisungen in C ++ durchführen, erhalten Sie schreckliche Zahlen.)

Stattdessen habe ich etwas mehr idiomatischen C ++ - Code geschrieben und mit dem bereitgestellten C # -Code @Wiory verglichen. Die zwei wichtigsten Änderungen, die ich am C ++ - Code vorgenommen habe, waren:

1) verwendeter Vektor :: Reserve ()

2) Reduzierte das 2d-Array auf 1d, um eine bessere Cache-Lokalität zu erreichen (zusammenhängender Block).

C # (.NET 4.6.1)

private static void TestArray()
{
    const int rows = 5000;
    const int columns = 9000;
    DateTime t1 = System.DateTime.Now;
    double[][] arr = new double[rows][];
    for (int i = 0; i < rows; i++)
        arr[i] = new double[columns];
    DateTime t2 = System.DateTime.Now;

    Console.WriteLine(t2 - t1);

    t1 = System.DateTime.Now;
    for (int i = 0; i < rows; i++)
        for (int j = 0; j < columns; j++)
            arr[i][j] = i;
    t2 = System.DateTime.Now;

    Console.WriteLine(t2 - t1);
}

Laufzeit (Release): Init: 124 ms, Fill: 165 ms

C ++ 14 (Clang v3.8 / C2)

#include <iostream>
#include <vector>

auto TestSuite::ColMajorArray()
{
    constexpr size_t ROWS = 5000;
    constexpr size_t COLS = 9000;

    auto initStart = std::chrono::steady_clock::now();

    auto arr = std::vector<double>();
    arr.reserve(ROWS * COLS);

    auto initFinish = std::chrono::steady_clock::now();
    auto initTime = std::chrono::duration_cast<std::chrono::microseconds>(initFinish - initStart);

    auto fillStart = std::chrono::steady_clock::now();

    for(auto i = 0, r = 0; r < ROWS; ++r)
    {
        for (auto c = 0; c < COLS; ++c)
        {
            arr[i++] = static_cast<double>(r * c);
        }
    }

    auto fillFinish = std::chrono::steady_clock::now();
    auto fillTime = std::chrono::duration_cast<std::chrono::milliseconds>(fillFinish - fillStart);

    return std::make_pair(initTime, fillTime);
}

Laufzeit (Release): Init: 398µs (ja, das sind Mikrosekunden), Fill: 152ms

Gesamtlaufzeiten: C #: 289 ms, C ++ 152 ms (ungefähr 90% schneller)

Beobachtungen

  • Das Ändern der C # -Implementierung auf dieselbe 1d-Array-Implementierung ergab Init: 40 ms, Fill: 171 ms, Total: 211 ms ( C ++ war immer noch fast 40% schneller ).

  • Es ist viel schwieriger, "schnellen" Code in C ++ zu entwerfen und zu schreiben, als "normalen" Code in beiden Sprachen zu schreiben.

  • Es ist (vielleicht) erstaunlich einfach, in C ++ eine schlechte Leistung zu erzielen. Wir haben das mit uneingeschränkter Vektorleistung gesehen. Und es gibt viele solche Fallstricke.

  • Die Leistung von C # ist ziemlich erstaunlich, wenn man bedenkt, was zur Laufzeit vor sich geht. Und diese Leistung ist vergleichsweise leicht zugänglich.

  • Weitere anekdotische Daten zum Vergleich der Leistung von C ++ und C #: https://benchmarksgame.alioth.debian.org/u64q/compare.php?lang=gpp&lang2=csharpcore

Unter dem Strich gibt Ihnen C ++ viel mehr Kontrolle über die Leistung. Möchten Sie einen Zeiger verwenden? Eine Referenz? Speicher stapeln? Haufen? Dynamischer Polymorphismus oder Eliminieren des Laufzeitaufwands einer vtable mit statischem Polymorphismus (über Templates / CRTP)? In C ++ müssen Sie ... äh, bekommen alle diese Entscheidungen (und mehr) selbst, am besten so , dass Ihre Lösung am besten Adressen das Problem Sie anpacken zu machen.

Fragen Sie sich, ob Sie diese Steuerung tatsächlich möchten oder benötigen, denn selbst für das obige triviale Beispiel können Sie feststellen, dass die Leistung zwar erheblich verbessert wird, für den Zugriff jedoch eine tiefere Investition erforderlich ist.


16
@ Quuuxux danke für den Kommentar. Natürlich ist dies kein "echtes Programm". Der Punkt der Benchmarks war die Umgestaltung eines C # -Benchmarks, der an anderer Stelle auf dieser Seite angeboten wird, als Beweis dafür, dass JITted-Code irgendwie schneller als nativ ist - es ist nicht so, und der Benchmark war möglicherweise für neue Leute irreführend.
U007D

9
@Quonux warum musst du so schreiben? Es sind Leute wie Sie, die mich dazu bringen, Stackoverflow nicht zu mögen.
Markus Knappen Johansson

5
@MarkusKnappenJohansson Ich hatte einen schlechten Tag;), ich bin auch nur ein Mensch, habe meine Ablehnung entfernt, aber meine Meinung gilt immer noch. Oh, bitte mag SO nicht, nur weil es einige "dumme" Leute gibt :). Ich wünsch dir was.
Quonux

9
VOLLSTÄNDIG FEHLENDE BANKMARKE. In der C ++ - Version reservieren Sie einfach einen Teil des Speichers (und wundern sich dann, wie die Ausführung dieses Vorgangs Mikrosekunden dauert). In der C # -Version erstellen Sie 5000 ARRAYS (Instanziieren von Objekten im Speicher). C ++ ist schneller als C # ... aber der Unterschied liegt bei weitem nicht bei 40% ... im Moment liegt er eher im Bereich von <10%. Ihr Beispiel zeigt, dass Programmierer bei der Sprache ihrer Wahl bleiben sollten (und aus Ihrem Profil geht hervor, dass Sie ein Karriere-C ++ - Programmierer sind). In C # können Sie 2D-Arrays erstellen int[,]... gefolgt von einem Beispiel.
Nikib3ro

3
Soweit ich das beurteilen kann, weist der Code in Ihrem C ++ - Beispiel buchstäblich nur den Speicher im Voraus zu. Die PROPER C # -Implementierung würde einfach 'List <double> arrs = new List <double> (ROWS * COLS)' schreiben, wodurch der Speicher zugewiesen wird, der zum Indizieren eines zweidimensionalen Arrays im eindimensionalen Format erforderlich ist (z. B. was Sie in C ++ getan haben). Es gibt absolut keinen Grund, ein zweidimensionales Array zuzuweisen und manuell zu reduzieren - die enorme Anzahl von Iterationen in Ihrem Vortest ist die Ursache für die beschissene Leistung. Ich stelle mir vor, dass der Overhead in C # immer noch höher wäre, aber nicht in erheblichem Maße.
JDSweetBeat

62

Nach meiner Erfahrung (und ich habe viel mit beiden Sprachen gearbeitet) ist das Hauptproblem bei C # im Vergleich zu C ++ der hohe Speicherverbrauch, und ich habe keinen guten Weg gefunden, dies zu steuern. Es war der Speicherverbrauch, der die .NET-Software letztendlich verlangsamen würde.

Ein weiterer Faktor ist, dass sich der JIT-Compiler nicht zu viel Zeit für erweiterte Optimierungen leisten kann, da er zur Laufzeit ausgeführt wird und der Endbenutzer dies bemerken würde, wenn er zu lange dauert. Andererseits verfügt ein C ++ - Compiler über die erforderliche Zeit, um zur Kompilierungszeit Optimierungen vorzunehmen. Dieser Faktor ist meiner Meinung nach viel weniger bedeutsam als der Speicherverbrauch.


6
In einem Projekt bei der Arbeit mussten wir gigantische Datenmengen abbauen, einschließlich des gleichzeitigen Speicherns vieler GB im Speicher und der Durchführung teurer Berechnungen - all dies erforderte eine genaue Kontrolle aller Zuordnungen, C ++ war so ziemlich die einzige Wahl. +1 für C ++. Auf der anderen Seite war dies nur ein Projekt. Wir haben die meiste Zeit damit verbracht, Systeme zu schreiben, die mit langsamen Simulatoren interagierten, und das Debuggen könnte ein Albtraum sein. Ich wünschte, wir hätten für all das andere eine Sprache zur Optimierung der Programmiererzeit verwenden können Sachen.
Bogatyr

7
@IngeHenriksen: Ich kenne das Dispose-Muster gut, aber es hilft überhaupt nicht beim verwalteten Speicher.
Nemanja Trifunovic

10
@IngeHenriksen, das es entsorgt, stellt nur sicher, dass die Dispose-Methode aufgerufen wurde. Durch die Entsorgung wird niemals Speicherplatz freigegeben. Die Dispose-Methode dient nur zum Bereinigen nicht verwalteter Ressourcen wie Dateihandles und hat nichts mit Speicherverwaltung zu tun.
Doug65536

1
@NemanjaTrifunovic: "Der JIT-Compiler kann sich nicht zu viel Zeit für erweiterte Optimierungen leisten." Können Sie einige Optimierungen anführen, die nicht von JITs durchgeführt werden, weil sie zu lange dauern würden?
Jon Harrop

5
@ user3800527: Auch wenn das Hinzufügen von RAM immer möglich war (und dies ist nicht der Fall - stellen Sie sich vor, Microsoft fügt jedem MS Office-Benutzer RAM hinzu), wird das Problem nicht gelöst. Der Speicher ist hierarchisch und ein C # -Programm weist viel mehr Cache-Fehler auf als ein C ++ - Programm.
Nemanja Trifunovic

35

Ein bestimmtes Szenario, in dem C ++ immer noch die Oberhand hat (und dies auch in den kommenden Jahren tun wird), tritt auf, wenn polymorphe Entscheidungen zur Kompilierungszeit vorbestimmt werden können.

Im Allgemeinen ist die Kapselung und verzögerte Entscheidungsfindung eine gute Sache, da sie den Code dynamischer macht, sich leichter an sich ändernde Anforderungen anpassen lässt und einfacher als Framework verwendet werden kann. Aus diesem Grund ist die objektorientierte Programmierung in C # sehr produktiv und kann unter dem Begriff „Generalisierung“ verallgemeinert werden. Leider ist diese spezielle Art der Verallgemeinerung zur Laufzeit mit Kosten verbunden.

Normalerweise sind diese Kosten nicht wesentlich, aber es gibt Anwendungen, bei denen der Aufwand für virtuelle Methodenaufrufe und die Objekterstellung einen Unterschied machen kann (insbesondere, da virtuelle Methoden andere Optimierungen wie das Inlining von Methodenaufrufen verhindern). Hier hat C ++ einen großen Vorteil, da Sie Vorlagen verwenden können, um eine andere Art der Verallgemeinerung zu erzielen, die keinen Einfluss auf die Laufzeit hat, aber nicht unbedingt weniger polymorph als OOP ist. Tatsächlich können alle Mechanismen, aus denen OOP besteht, nur mit Vorlagentechniken und einer Auflösung zur Kompilierungszeit modelliert werden.

In solchen Fällen (und zugegebenermaßen sind sie häufig auf spezielle Problemdomänen beschränkt) gewinnt C ++ gegen C # und vergleichbare Sprachen.


6
Tatsächlich sind Java-VMs (und wahrscheinlich .NET) sehr bemüht, einen dynamischen Versand zu vermeiden. Wenn es eine Möglichkeit gibt, Polymorphim zu vermeiden, können Sie ziemlich sicher sein, dass Ihre VM dies tut.
Martin Probst

3
+1 Ich habe immer Probleme, dies meinen C # -Kollegen zu erklären, die wenig C ++ so kennen, dass sie die Bedeutung einschätzen können. Du hast es ziemlich nett erklärt.
Roman Starkov

9
@crtracy: Sie machen Ihre Wette ohne Hochleistungs-Computeranwendungen. Berücksichtigen Sie Wettervorhersagen, Bioinformatik und numerische Simulationen. Der Leistungsvorsprung von C ++ in diesen Bereichen wird nicht verringert, da kein anderer Code eine vergleichbare Leistung bei gleichem Grad an hoher Abstraktion erzielen kann.
Konrad Rudolph

5
@ Jon Äpfel und Orangen. Ihre spezifische Behauptung lautete: "C # ist im Kontext der Metaprogrammierung um Größenordnungen schneller als C ++", nicht "Die Verwendung von vorkompiliertem Code ist um Größenordnungen schneller als interpretierter Code". Während wir gerade dabei sind, ist Ihre Behauptung, dass die Generierung von Laufzeitcode „allgemeiner“ ist als die Generierung von Code zur Kompilierungszeit, ebenfalls eindeutig falsch - beide haben Stärken und Schwächen. Bei der Codegenerierung zur Kompilierungszeit wird das Typsystem verwendet, um statische Typensicherheit zu gewährleisten. Die Laufzeitcodegenerierung kann dies nicht (dies kann eine starke Typensicherheit bieten, jedoch keine statische Typensicherheit).
Konrad Rudolph

5
@ user3800527 Ich denke, Sie verpassen den ganzen Punkt dieser Antwort. Natürlich können Sie dies umgehen, indem Sie die Kapselung aufheben und auf Strukturen auf niedriger Ebene zurückgreifen - Sie können Assemblierungen in (fast) jeder Sprache schreiben. Das, was C ++ (fast) einzigartig und einzigartig für Hochleistungsprogrammierung geeignet macht, ist, dass Sie Abstraktionen auf hoher Ebene erstellen können , die ohne Laufzeitkosten verfügbar sind. Sie müssen also keinen Assembler-ähnlichen Code in C ++ schreiben, um eine erstklassige Leistung zu erzielen: Eine gut sort(arr, generic_comparer)geschriebene Schleife ist so effizient wie eine handgeschriebene Schleife in C ++. Es wird niemals in C # sein.
Konrad Rudolph

20

Mit C ++ (oder C) können Sie Ihre Datenstrukturen genau steuern. Wenn Sie etwas drehen möchten, haben Sie diese Option. Große verwaltete Java- oder .NET-Apps (OWB, Visual Studio 2005 ), die die internen Datenstrukturen der Java / .NET-Bibliotheken verwenden, tragen das Gepäck mit sich. Ich habe gesehen, wie OWB-Designer-Sitzungen mit über 400 MB RAM und BIDS für das Cube- oder ETL- Design auch in die 100 MB kamen.

Bei einer vorhersehbaren Arbeitslast (wie den meisten Benchmarks, die einen Prozess viele Male wiederholen) kann eine JIT Ihnen Code liefern, der so gut optimiert ist, dass es keinen praktischen Unterschied gibt.

IMO bei großen Anwendungen ist der Unterschied weniger die JIT als die Datenstrukturen, die der Code selbst verwendet. Wenn eine Anwendung speicherintensiv ist, wird der Cache weniger effizient genutzt. Cache-Fehler auf modernen CPUs sind ziemlich teuer. Wenn C oder C ++ wirklich gewinnen, können Sie die Verwendung von Datenstrukturen optimieren, um mit dem CPU-Cache gut zu spielen.


19

Für Grafiken ist die Standardklasse C # Graphics viel langsamer als GDI, auf das über C / C ++ zugegriffen wird. Ich weiß, dass dies nichts mit der Sprache an sich zu tun hat, sondern eher mit der gesamten .NET-Plattform, aber Grafik wird dem Entwickler als GDI-Ersatz angeboten, und die Leistung ist so schlecht, dass ich es nicht einmal wagen würde, Grafiken zu erstellen damit.

Wir haben einen einfachen Benchmark, mit dem wir sehen, wie schnell eine Grafikbibliothek ist, und der einfach zufällige Linien in einem Fenster zeichnet. C ++ / GDI ist mit 10000 Zeilen immer noch bissig, während C # / Graphics Schwierigkeiten hat, 1000 in Echtzeit auszuführen.


5
Ihre Antwort hat mich fasziniert. Haben Sie denselben Benchmark mit unsicherem Code und Lockbits getestet und die zufälligen Linien selbst gezogen? Nun das wäre eine interessante Sache sein , zu betrachten.
Pedery

2
@Pedery nein habe ich nicht. Verwenden Sie einfach GDI und .NET.Graphics auf einfachste Weise. Was meinst du mit "selbst die zufälligen Linien zeichnen"?
QBziZ

1
Dann sollten Sie vielleicht überlegen, dies zu testen, um realistischere Metriken dafür zu erhalten, wie schnell C # sein kann. Hier ist ein schöner Überblick über die Technik: bobpowell.net/lockingbits.htm
Pedery

6
Das ist nicht das, was wir tun wollen, indem wir separate Pixel selbst in einen Bildpuffer einfügen. Wenn Sie alles selbst implementieren müssen, was bringt es, eine API / Plattform zum Codieren zu haben? Für mich ist das kein Argument. Wir mussten in GDI nie separate Pixel in einen Framebuffer einfügen, um Linien zu zeichnen, und wir planen dies auch nicht in .NET. Meiner Ansicht nach haben wir eine realistische Metrik verwendet, und .NET hat sich als langsam herausgestellt.
QBziZ

1
Nun, ich habe nur eine kleine Vorstellung davon, was Blob-Erkennung ist, aber nur ein Timing anzugeben, beweist eher gar nichts. Hast du einen in C ++ geschrieben? In JavaScript? Und diese mit denen in C # verglichen? Außerdem glaube ich nicht, dass bei der Blob-Erkennung viele Grafikprimitive verwendet werden. Korrigieren Sie mich, wenn Sie falsch liegen, aber ich denke, es sind statistische Algorithmen, die Operationen an Pixeln ausführen.
QBziZ

13

Die Speicherbereinigung ist der Hauptgrund, warum Java # NICHT für Echtzeitsysteme verwendet werden kann.

  1. Wann wird der GC stattfinden?

  2. Wie lange wird es dauern?

Dies ist nicht deterministisch.


5
Ich bin kein großer Java-Fan, aber es gibt nichts, was besagt, dass Java keinen Echtzeit-freundlichen GC verwenden kann.
Zan Lynx

5
Es gibt viele Echtzeit-GC-Implementierungen, wenn Sie sich das ansehen möchten. (GC ist ein Gebiet, das mit Forschungsarbeiten überfüllt ist )
Arafangion

FWIW, Richard Jones hat gerade eine aktualisierte Version seines Müllsammelbuchs veröffentlicht, die unter anderem hochmoderne Echtzeit-GC-Designs enthält.
Jon Harrop

11
Dies ist ein Unsinnsargument. Windows (und Linux) sind keine Echtzeitbetriebssysteme. Ihr C ++ - Code kann jederzeit auch für mehrere 18-ms-Slots ausgetauscht werden.
Henk Holterman

2
@HenkHolterman Stimmt, aber Sie können jederzeit einen Bootloader in Assembly schreiben, diesen in einen Kernel-Bootstrap für Ihre Anwendung einbinden und Ihre C ++ - Apps direkt auf der Hardware ausführen (übrigens in RT). Sie können dies nicht in C # tun, und alle Bemühungen, die ich gesehen habe, ahmen nur vorkompilierte Assemblys in C # nach und verwenden eine Menge C-Code, wodurch die Verwendung von C # sinnlos wird. Das alles zu lesen ist ein bisschen lustig, weil C # ohne das .NET Framework wirklich nutzlos ist.
zackery.fix

11

Wir mussten feststellen, ob C # in der Leistung mit C ++ vergleichbar war, und ich habe einige Testprogramme dafür geschrieben (mit Visual Studio 2005 für beide Sprachen). Es stellte sich heraus, dass C # ohne Garbage Collection und nur unter Berücksichtigung der Sprache (nicht des Frameworks) im Grunde die gleiche Leistung wie C ++ hat. Die Speicherzuweisung ist in C # viel schneller als in C ++, und C # weist einen leichten Determinismus auf, wenn die Datengröße über die Grenzen der Cache-Zeilen hinaus erhöht wird. All dies musste jedoch irgendwann bezahlt werden, und es entstehen enorme Kosten in Form von nicht deterministischen Leistungstreffern für C # aufgrund der Speicherbereinigung.


1
In C ++ haben Sie die Möglichkeit, verschiedene Zuweisungsmethoden zu verwenden. Je nachdem, wie Speicher in C # zugewiesen wurde (AOT?), Kann dies in C ++ auf die gleiche Weise (aber viel schneller) erfolgen.
zackery.fix

5
@ zackery.fix .NET hat einen interessanten Vorteil bei der Heap-Zuweisung, da nur ein Zeiger verschoben werden muss, um ein neues Objekt zuzuweisen. Dies ist nur aufgrund des verdichtenden Müllsammlers möglich. Natürlich können Sie dasselbe in C ++ tun, aber C ++ tut das nicht. Es ist lustig, wie Sie das gleiche Argument verwenden, um zu sagen "C # könnte, aber nicht, also ist es Müll" und "C ++ nicht, aber es könnte, also ist es fantastisch" :)
Luaan

9

Wie immer kommt es auf die Anwendung an. Es gibt Fälle, in denen C # wahrscheinlich vernachlässigbar langsamer ist, und andere Fälle, in denen C ++ fünf- oder zehnmal schneller ist, insbesondere in Fällen, in denen Vorgänge leicht SIMD-fähig sind.


Der beste Fall für VMs ist die Laufzeitkompilierung des generierten Codes (z. B. um einem zur Laufzeit eingelesenen regulären Ausdruck zu entsprechen), da statisch kompilierte Vanilla C ++ - Programme nur dann interpretiert werden können, wenn kein JIT-Compiler integriert ist.
Jon Harrop

Hinweis aus der Zukunft: .NET unterstützt SIMD und Freunde seit etwa 2014, obwohl es nicht weit verbreitet ist.
Luaan

9

Ich weiß, dass es nicht das ist, was Sie gefragt haben, aber C # ist oft schneller zu schreiben als C ++, was in einem kommerziellen Umfeld ein großer Bonus ist.


2
Ich würde sagen, es ist die meiste Zeit schneller :)
Falle

8

C / C ++ kann in Programmen, in denen entweder große Arrays oder starke Schleifen / Iterationen über Arrays (beliebiger Größe) vorhanden sind, erheblich besser abschneiden. Dies ist der Grund, warum Grafiken in C / C ++ im Allgemeinen viel schneller sind, da fast allen Grafikoperationen schwere Array-Operationen zugrunde liegen. .NET ist bei Array-Indizierungsvorgängen aufgrund aller Sicherheitsüberprüfungen notorisch langsam, und dies gilt insbesondere für mehrdimensionale Arrays (und ja, rechteckige C # -Arrays sind sogar langsamer als gezackte C # -Arrays).

Die Boni von C / C ++ sind am ausgeprägtesten, wenn Sie sich direkt an Zeiger halten und Boost std::vectorund andere hochrangige Container sowie inlinejede mögliche kleine Funktion vermeiden . Verwenden Sie nach Möglichkeit Arrays der alten Schule. Ja, Sie benötigen mehr Codezeilen, um das Gleiche wie in Java oder C # zu erreichen, da Sie Container auf hoher Ebene vermeiden. Wenn Sie ein Array mit dynamischer Größe benötigen, müssen Sie nur daran denken, Ihr Array new T[]mit einer entsprechenden delete[]Anweisung zu koppeln (oder zu verwenden)std::unique_ptr) - Der Preis für die zusätzliche Geschwindigkeit ist, dass Sie sorgfältiger codieren müssen. Im Gegenzug können Sie sich jedoch vom Overhead des verwalteten Speichers / Garbage Collectors befreien, der leicht 20% oder mehr der Ausführungszeit stark objektorientierter Programme in Java und .NET sowie der massiv verwalteten Programme ausmachen kann Indizierungskosten für Speicherarrays. C ++ - Apps können in bestimmten Fällen auch von einigen raffinierten Compiler-Switches profitieren.

Ich bin ein erfahrener Programmierer in C, C ++, Java und C #. Ich hatte kürzlich die seltene Gelegenheit, genau das gleiche algorithmische Programm in den letzten drei Sprachen zu implementieren. Das Programm hatte viele mathematische und mehrdimensionale Array-Operationen. Ich habe dies in allen 3 Sprachen stark optimiert. Die Ergebnisse waren typisch für das, was ich normalerweise in weniger strengen Vergleichen sehe: Java war ungefähr 1,3-mal schneller als C # (die meisten JVMs sind optimierter als die CLR), und die C ++ - Rohzeigerversion war ungefähr 2,1-mal schneller als C #. Beachten Sie, dass das C # -Programm nur sicheren Code verwendet hat. Meiner Meinung nach können Sie ihn auch in C ++ codieren, bevor Sie das unsafeSchlüsselwort verwenden.

Damit niemand glaubt, ich hätte etwas gegen C #, möchte ich abschließend sagen, dass C # wahrscheinlich meine Lieblingssprache ist. Es ist die logischste, intuitivste und schnellste Entwicklungssprache, die mir bisher begegnet ist. Ich mache alle meine Prototypen in C #. Die C # -Sprache hat viele kleine, subtile Vorteile gegenüber Java (ja, ich weiß, dass Microsoft die Möglichkeit hatte, viele der Mängel von Java zu beheben, indem es spät ins Spiel kam und wohl Java kopierte). Toast auf Javas CalendarKlasse? Sollte Microsoft jemals echte Anstrengungen unternehmen, um die CLR und den .NET JITter zu optimieren, könnte C # ernsthaft die Kontrolle übernehmen. Ich bin ehrlich überrascht, dass sie es noch nicht getan haben - sie haben so viele Dinge richtig in der C # -Sprache gemacht. Warum nicht mit schlagkräftigen Compiler-Optimierungen weitermachen? Vielleicht, wenn wir alle betteln.


3
"Sie müssen nur daran denken, Ihre new T[]mit einer entsprechenden zu koppeln delete[]" - Nein, tun Sie nicht. Das muss std::unique_ptrich für dich tun.
Emlai

Angenommen, Sie haben etwas in Grafiken geschrieben. Warum sollten Sie sicheren Code in c # schreiben? Haben Sie darüber nachgedacht, unsicheren Code zu verwenden und erneut zu vergleichen?
user3800527

7

> Nach dem, was ich gehört habe ...

Ihre Schwierigkeit scheint darin zu liegen, zu entscheiden, ob das, was Sie gehört haben, glaubwürdig ist, und diese Schwierigkeit wird nur wiederholt, wenn Sie versuchen, die Antworten auf dieser Site zu bewerten.

Wie werden Sie entscheiden, ob die Dinge, die die Leute hier sagen, mehr oder weniger glaubwürdig sind als das, was Sie ursprünglich gehört haben?

Eine Möglichkeit wäre, nach Beweisen zu fragen .

Wenn jemand behauptet, "es gibt Bereiche, in denen sich C # als schneller als C ++ erweist", fragen Sie ihn, warum er das sagt , bitten Sie ihn, Ihnen Messungen zu zeigen, und bitten Sie ihn, Ihnen Programme zu zeigen. Manchmal haben sie einfach einen Fehler gemacht. Manchmal werden Sie feststellen, dass sie nur eine Meinung äußern, anstatt etwas zu teilen, von dem sie zeigen können, dass es wahr ist.

Oft werden Informationen und Meinungen in den Behauptungen der Leute verwechselt, und Sie müssen versuchen, herauszufinden, welche welche ist. Zum Beispiel aus den Antworten in diesem Forum:

  • "Nehmen Sie die Benchmarks unter http://shootout.alioth.debian.org/ mit großer Skepsis, da diese weitgehend arithmetischen Code testen, der Ihrem Code höchstwahrscheinlich überhaupt nicht ähnlich ist."

    Fragen Sie sich, ob Sie wirklich verstehen, was "dieser weitgehend testweise arithmetische Code" bedeutet, und fragen Sie sich dann, ob der Autor Ihnen tatsächlich gezeigt hat, dass seine Behauptung wahr ist.

  • "Das ist ein ziemlich nutzloser Test, da es wirklich darauf ankommt, wie gut die einzelnen Programme optimiert wurden. Ich habe es geschafft, einige davon um das 4-6-fache oder mehr zu beschleunigen, was deutlich macht, dass der Vergleich zwischen nicht optimierten Programmen eher ist dumm."

    Fragen Sie sich, ob der Autor Ihnen tatsächlich gezeigt hat, dass er es geschafft hat, "einige von ihnen um das 4-6-fache oder mehr zu beschleunigen" - es ist eine einfache Behauptung!


Ich könnte dir nicht mehr zustimmen und das ist der Grund, warum ich in diesem Forum gefragt habe ... Schließlich müssen die Antworten irgendwo sein, nicht wahr? :)
Falle

1
Ja. Die Antwort lautet "Es kommt darauf an."
user49117

6

Bei "peinlich parallelen" Problemen habe ich bei Verwendung von Intel TBB und OpenMP unter C ++ eine etwa 10-fache Leistungssteigerung im Vergleich zu ähnlichen (rein mathematischen) Problemen mit C # und TPL beobachtet. SIMD ist ein Bereich, in dem C # nicht mithalten kann, aber ich hatte auch den Eindruck, dass TPL einen beträchtlichen Overhead hat.

Trotzdem verwende ich C ++ nur für leistungskritische Aufgaben, bei denen ich weiß, dass ich Multithreading durchführen und schnell Ergebnisse erzielen kann. Für alles andere ist C # (und gelegentlich F #) in Ordnung.


5

Es ist eine äußerst vage Frage ohne echte endgültige Antworten.

Beispielsweise; Ich spiele lieber 3D-Spiele, die in C ++ erstellt wurden, als in C #, da die Leistung sicherlich viel besser ist. (Und ich kenne XNA usw., aber es kommt der Realität nicht nahe).

Andererseits, wie zuvor erwähnt; Sie sollten sich in einer Sprache entwickeln, mit der Sie schnell das tun können, was Sie wollen, und dann bei Bedarf optimieren.


4
Können Sie einige Beispiele nennen? Spiele in C # geschrieben, was Sie langsam gefunden haben
Karl

1
Sogar die Beispielanwendungen, die mit der Installation geliefert wurden, fühlten sich langsam an.
David The Man

9
Der Garbage Collector ist eine große Gefahr bei der Erstellung von Spielen mit C #, da er jederzeit einspringen und zu großen Pausen führen kann. Die explizite Speicherverwaltung ist für die Spieleentwicklung einfacher.
Postfuturist

3
Die meisten modernen Spiele sind GPU-begrenzt. Für solche Spiele spielt es keine Rolle, ob die Logik (auf der CPU ausgeführt) 10% langsamer ist, sie sind immer noch durch die GPU und nicht durch die CPU begrenzt. Garbage Collector ist ein echtes Problem, das zufällige kurze Einfrierungen verursacht, wenn die Speicherzuordnungen nicht gut abgestimmt sind.
Michael Entin

2
@postfuturist: Das stimmt auf dem PC nicht; Der Müllsammler macht so gute Arbeit beim Ein- und Aussteigen. Ich hatte noch nie Probleme damit. Doch auf XBox 360 und Zune / Windows 7-Telefon, ist die Garbage Collector nicht fast so intelligent wie auf dem PC; Ich habe auch noch nie dafür geschrieben, aber Leute, die mir den Müllsammler erzählt haben , sind ein großes Problem.
BlueRaja - Danny Pflughoeft

5

.NET-Sprachen können so schnell wie C ++ - Code oder sogar noch schneller sein, aber C ++ - Code hat einen konstanteren Durchsatz, da die .NET-Laufzeit für GC angehalten werden muss , selbst wenn die Pausen sehr clever sind.

Also , wenn Sie einen Code haben, der konstant schnell hat zu laufen , ohne Pause, wird .NET vorstellen Latenz an einem gewissen Punkt , auch wenn Sie sehr vorsichtig mit dem Runtime - GC.


6
-1: Das ist eigentlich ein Mythos. Erstens ist die Latenz von idiomatischem C ++ tatsächlich schrecklich und oft viel schlimmer als .NET, da RAII Lawinen von Destruktoren verursacht, wenn große Datenstrukturen nicht mehr in den Geltungsbereich fallen, während moderne GCs inkrementell sind und .NETs sogar gleichzeitig auftreten. Zweitens können Sie GC-Pausen in .NET vollständig entfernen, indem Sie sie nicht zuordnen.
Jon Harrop

2
Wenn Sie dies tun, müssen Sie auf die Verwendung der BCL verzichten, da die meisten Methoden vorübergehende Objekte erstellen.
Florian Doyon

5
Dies ist ganz richtig, erst mit .net 4 wurde der GC inkrementell gemacht. Wir haben eine große C # -App, die für GC jeweils für Sekunden pausiert. Für leistungskritische Apps ist dies ein Killer.
Justin

5
Es gibt einen Grund, warum Programme, die dazu neigen, die Hardware zu pushen, dazu neigen, C ++ zu verwenden. Sie haben eine feinere Steuerung, wenn Sie sie brauchen. Die Leistung ist nur dann von entscheidender Bedeutung, wenn Sie das System vorantreiben. Verwenden Sie andernfalls C # oder Java, um Zeit zu sparen.
VoronoiPotato

4
Wenn Sie das Cache-Verhalten nicht verwalten können, können Sie optimierten C ++ - Code nicht übertreffen. Ein Cache-Fehler von L1 zum Hauptspeicher kann Ihren Betrieb 100-mal verlangsamen.
DAG

4

Theoretisch kann eine JIT-kompilierte Sprache für Anwendungen mit langem Servertyp viel schneller werden als ein nativ kompiliertes Gegenstück. Da die kompilierte JIT-Sprache in der Regel zuerst in eine relativ einfache Zwischensprache kompiliert wird, können Sie viele der Optimierungen auf hoher Ebene ohnehin direkt zur Kompilierungszeit durchführen. Der große Vorteil besteht darin, dass die JIT weiterhin Codeabschnitte im laufenden Betrieb neu kompilieren kann, da immer mehr Daten über die Verwendung der Anwendung abgerufen werden. Es kann die gängigsten Codepfade anordnen, damit die Verzweigungsvorhersage so oft wie möglich erfolgreich ist. Es kann separate Codeblöcke neu anordnen, die häufig zusammen aufgerufen werden, um beide im Cache zu halten. Es kann mehr Aufwand aufwenden, um innere Schleifen zu optimieren.

Ich bezweifle, dass dies von .NET oder einem der JREs durchgeführt wird, aber es wurde bereits während meines Studiums untersucht. Es ist daher nicht unangemessen zu glauben, dass solche Dinge bald ihren Weg in die reale Welt finden könnten .


4

Anwendungen, die einen intensiven Speicherzugriff erfordern, z. Bildmanipulationen sind normalerweise besser in einer nicht verwalteten Umgebung (C ++) als in einer verwalteten Umgebung (C #) geschrieben. Optimierte innere Schleifen mit Zeigerarithmetik sind in C ++ viel einfacher zu steuern. In C # müssen Sie möglicherweise auf unsicheren Code zurückgreifen, um die gleiche Leistung zu erzielen.


4

Ich habe vectorin C ++ und C # -Äquivalenten getestet - Listund in einfachen 2D-Arrays.

Ich verwende Visual C # / C ++ 2010 Express-Editionen. Beide Projekte sind einfache Konsolenanwendungen. Ich habe sie im Standard-Release- und Debug-Modus (keine benutzerdefinierten Einstellungen) getestet. C # -Listen laufen auf meinem PC schneller, die Array-Initialisierung ist auch in C # schneller, mathematische Operationen sind langsamer.

Ich verwende Intel Core2Duo P8600@2.4GHz, C # - .NET 4.0.

Ich weiß, dass sich die Vektorimplementierung von der C # -Liste unterscheidet, aber ich wollte nur Sammlungen testen, die ich zum Speichern meiner Objekte verwenden würde (und die den Index-Accessor verwenden können).

Natürlich müssen Sie den Speicher löschen (sagen wir für jede Verwendung von new), aber ich wollte den Code einfach halten.

C ++ Vektortest :

static void TestVector()
{
    clock_t start,finish;
    start=clock();
    vector<vector<double>> myList=vector<vector<double>>();
    int i=0;
    for( i=0; i<500; i++)
    {
        myList.push_back(vector<double>());
        for(int j=0;j<50000;j++)
            myList[i].push_back(j+i);
    }
    finish=clock();
    cout<<(finish-start)<<endl;
    cout<<(double(finish - start)/CLOCKS_PER_SEC);
}

C # -Listentest:

private static void TestVector()
{

    DateTime t1 = System.DateTime.Now;
    List<List<double>> myList = new List<List<double>>();
    int i = 0;
    for (i = 0; i < 500; i++)
    {
        myList.Add(new List<double>());
        for (int j = 0; j < 50000; j++)
            myList[i].Add(j *i);
    }
    DateTime t2 = System.DateTime.Now;
    Console.WriteLine(t2 - t1);
}

C ++ - Array:

static void TestArray()
{
    cout << "Normal array test:" << endl;
    const int rows = 5000;
    const int columns = 9000;
    clock_t start, finish;

    start = clock();
    double** arr = new double*[rows];
    for (int i = 0; i < rows; i++)
        arr[i] = new double[columns];
    finish = clock();

    cout << (finish - start) << endl;

    start = clock();
    for (int i = 0; i < rows; i++)
        for (int j = 0; j < columns; j++)
            arr[i][j] = i * j;
    finish = clock();

    cout << (finish - start) << endl;
}

C # - Array:

private static void TestArray()
{
    const int rows = 5000;
    const int columns = 9000;
    DateTime t1 = System.DateTime.Now;
    double[][] arr = new double[rows][];
    for (int i = 0; i < rows; i++)
        arr[i] = new double[columns];
    DateTime t2 = System.DateTime.Now;

    Console.WriteLine(t2 - t1);

    t1 = System.DateTime.Now;
    for (int i = 0; i < rows; i++)
        for (int j = 0; j < columns; j++)
            arr[i][j] = i * j;
    t2 = System.DateTime.Now;

    Console.WriteLine(t2 - t1);

}

Zeit: (Release / Debug)

C ++

  • 600/606 ms Array init,
  • 200/270 ms Arrayfüllung,
  • 1sec / 13sec Vektorinit & Fill.

(Ja, 13 Sekunden, ich habe immer Probleme mit Listen / Vektoren im Debug-Modus.)

C #:

  • 20/20 ms Array init,
  • 403/440 ms Arrayfüllung,
  • 710/742 ms Liste init & fill.

1
Ich würde gerne den Index-Accessor in std :: list sehen. Wie auch immer, es dauert 37 Sekunden mit Liste, Release-Modus. Release ohne Debugging: 3s Liste, 0,3 s Vektor. Wahrscheinlich Dereferenzierungsproblem oder etw. Beispiel: nopaste.pl/12fb
Wiory

2
Für genauere Messungen sollten Sie nicht System.DateTime.Nowdie Stoppuhrklasse verwenden .
Sam

4
Ein Grund dafür, dass Sie in C ++ so langsame Füllzeiten für den Vektor erhalten, ist die Verwendung von push_back. Bei zahlreichen Posts wurde gezeigt, dass dies langsamer ist als bei Verwendung der at-Methode oder des Operators []. Um eine dieser Methoden verwenden zu können, müssen Sie die Größenänderungs- oder Reservemethode verwenden. Der Grund, warum Ihre Initialisierung für den Fall eines C ++ - Vektors so lange dauert, ist, dass Sie einen Kopier- oder Zuweisungsoperator (in diesem Fall nicht sicher) zwingen, Ihren C ++ - Vektor zu initialisieren. Für das Array in c ++ gibt es einen Algorithmus, der 2 neue Aufrufe anstelle von 5001 verwendet und auch schneller iteriert.
Zachary Kraus

5
Ich denke, Sie haben C ++ nicht angemessen gemacht. Nur ein Blick und fand so viele Probleme. ZB Vektor <Vektor <double>> myList = Vektor <Vektor <double>> ()
DAG

2
Beeindruckend. Sie sind sich nicht sicher, welche Schlussfolgerungen Sie aus dem Vergleich von Listen mit Arrays mit veränderbarer Größe ziehen können, aber wenn Sie solche Vektoren verwenden, sollten Sie etwas über Reserve (), meinen Freund, Reserve () lernen.
U007D

3

Es hängt davon ab. Wenn der Bytecode in Maschinencode übersetzt wird (und nicht nur in JIT) (ich meine, wenn Sie das Programm ausführen) und wenn Ihr Programm viele Zuweisungen / Freigaben verwendet, kann dies schneller sein, da der GC- Algorithmus nur einen Durchgang benötigt (theoretisch) einmal durch den gesamten Speicher, aber normale malloc / realloc / free C / C ++ - Aufrufe verursachen einen Overhead bei jedem Aufruf (Call-Overhead, Datenstruktur-Overhead, Cache-Fehler;)).

So ist es theoretisch möglich (auch für andere GC-Sprachen).

Ich sehe nicht wirklich den extremen Nachteil, Metaprogrammierung mit C # für die meisten Anwendungen nicht verwenden zu können, da die meisten Programmierer sie sowieso nicht verwenden.

Ein weiterer großer Vorteil ist, dass SQL wie die LINQ "-Erweiterung" dem Compiler die Möglichkeit bietet, Aufrufe von Datenbanken zu optimieren (mit anderen Worten, der Compiler könnte den gesamten LINQ zu einer "Blob" -Binärdatei kompilieren, in der die aufgerufenen Funktionen inline oder inline sind für Ihren Einsatz optimiert, aber ich spekuliere hier).


1
Jeder richtige C ++ - Entwickler wird nicht auf die von Ihnen beschriebenen Probleme stoßen. Nur schlechte C-Programmierer, die beschlossen haben, Klassen auf ihre Programme zu setzen und sie C ++ zu nennen, haben diese Probleme.
Klarer

1
Aus Liebe zu Göttern ist dies 8 Jahre alt, OMFGz
Quonux

Fühlen Sie sich frei, eine bessere, aktuellere Antwort zu geben
Quonux

2

Ich nehme an, es gibt in C # geschriebene Anwendungen, die schnell laufen, und es gibt mehr C ++ - geschriebene Apps, die schnell laufen (C ++ ist nur älter ... und auch UNIX ...)
- die Frage ist in der Tat - was ist das für ein Ding, Benutzer und Entwickler beschweren sich über ...
Nun, IMHO, im Fall von C # haben wir eine sehr komfortable Benutzeroberfläche, eine sehr schöne Hierarchie von Bibliotheken und ein ganzes Schnittstellensystem von CLI. Im Fall von C ++ haben wir Vorlagen, ATL, COM, MFC und eine ganze Reihe von bereits geschriebenem und laufendem Code wie OpenGL, DirectX usw. ... Entwickler beklagen sich über unbestimmt gestiegene GC-Aufrufe im Fall von C # (bedeutet, dass das Programm schnell läuft, und in einer Sekunde - Knall! Es steckt fest).
Das Schreiben von Code in C # ist sehr einfach und schnell (nicht zu vergessen, dass dies auch die Fehlerwahrscheinlichkeit erhöht. Im Falle von C ++ klagen Entwickler über Speicherlecks, - bedeutet Quetschungen, Aufrufe zwischen DLLs sowie "DLL-Hölle" - Probleme mit Support- und Ersatzbibliotheken durch neuere ...
Ich denke, je mehr Kenntnisse Sie in der Programmiersprache haben, desto mehr Qualität (und Geschwindigkeit) werden Ihre Software charakterisieren.


2

Ich würde es so ausdrücken: Programmierer, die schnelleren Code schreiben, sind diejenigen, die besser darüber informiert sind, was aktuelle Maschinen schnell macht, und im Übrigen sind sie auch diejenigen, die ein geeignetes Werkzeug verwenden, das präzise Low-Level- und Deterministik ermöglicht Optimierungstechniken. Aus diesen Gründen verwenden diese Personen C / C ++ anstelle von C #. Ich würde so weit gehen, dies als Tatsache zu bezeichnen.


Notch hat Minecraft so codiert, dass es angesichts der Datenmenge, die er manipuliert, ziemlich schnell ist. Außerdem codierte er es größtenteils im Alleingang in vergleichsweise kurzer Zeit, was in C ++ praktisch unmöglich gewesen wäre. Ich bin jedoch mit den Optimierungstechniken einverstanden - wenn Sie die zusätzliche 10-fache Entwicklungszeit haben, damit Ihr Code doppelt so schnell ausgeführt wird, lohnt es sich wahrscheinlich.
Bill K

2

Wenn ich mich nicht irre, werden C # -Vorlagen zur Laufzeit ermittelt. Dies muss langsamer sein als die Kompilierungszeitvorlagen von C ++.

Und wenn Sie alle anderen von so vielen anderen erwähnten Optimierungen zur Kompilierungszeit sowie den Mangel an Sicherheit berücksichtigen, der in der Tat mehr Geschwindigkeit bedeutet ...

Ich würde sagen, C ++ ist die offensichtliche Wahl in Bezug auf Rohgeschwindigkeit und minimalen Speicherverbrauch. Dies bedeutet jedoch auch mehr Zeit für die Entwicklung des Codes und die Sicherstellung, dass kein Speicher verloren geht oder Nullzeigerausnahmen verursacht werden.

Urteil:

  • C #: Schnellere Entwicklung, langsamerer Lauf

  • C ++: Langsame Entwicklung, schnellerer Lauf.


1

Es hängt wirklich davon ab, was Sie in Ihrem Code erreichen möchten. Ich habe gehört, dass es nur eine urbane Legende ist, dass es einen Leistungsunterschied zwischen VB.NET, C # und verwaltetem C ++ gibt. Zumindest bei String-Vergleichen habe ich jedoch festgestellt, dass C ++ die Hosen von C # schlägt, was wiederum die Hosen von VB.NET schlägt.

Ich habe keineswegs erschöpfende Vergleiche in der algorithmischen Komplexität zwischen den Sprachen durchgeführt. Ich verwende auch nur die Standardeinstellungen in jeder der Sprachen. In VB.NET verwende ich Einstellungen, um die Deklaration von Variablen usw. zu erfordern. Hier ist der Code, den ich für verwaltetes C ++ verwende: (Wie Sie sehen können, ist dieser Code recht einfach). Ich verwende dasselbe in den anderen Sprachen in Visual Studio 2013 mit .NET 4.6.2.

#include "stdafx.h"

using namespace System;
using namespace System::Diagnostics;

bool EqualMe(String^ first, String^ second)
{
    return first->Equals(second);
}
int main(array<String ^> ^args)
{
    Stopwatch^ sw = gcnew Stopwatch();
    sw->Start();
    for (int i = 0; i < 100000; i++)
    {
        EqualMe(L"one", L"two");
    }
    sw->Stop();
    Console::WriteLine(sw->ElapsedTicks);
    return 0;
}

1

In Bezug auf den Leistungsaspekt gibt es einige wesentliche Unterschiede zwischen C # und C ++:

  • C # basiert auf GC / Heap. Die Zuweisung und der GC selbst sind Overhead als Nichtlokalität des Speicherzugriffs
  • C ++ - Optimierer sind im Laufe der Jahre sehr gut geworden. JIT-Compiler können nicht das gleiche Level erreichen, da sie nur eine begrenzte Kompilierungszeit haben und den globalen Bereich nicht sehen

Daneben spielt auch die Programmiererkompetenz eine Rolle. Ich habe schlechten C ++ - Code gesehen, in dem Klassen überall als Argument als Wert übergeben wurden. Sie können die Leistung in C ++ tatsächlich verschlechtern, wenn Sie nicht wissen, was Sie tun.


0

> Die Antworten müssen doch irgendwo sein, oder? :) :)

Ähm nein.

Wie in mehreren Antworten erwähnt, ist die Frage so unterbestimmt, dass Fragen als Antwort und keine Antworten eingeladen werden. Um nur einen Weg zu gehen:

Und welche Programme? Welche Maschine? Welches Betriebssystem? Welcher Datensatz?


Ich stimme vollkommen zu. Ich frage mich, warum die Leute eine genaue Antwort erwarten (63,5%), wenn sie eine allgemeine Frage stellen. Ich glaube nicht, dass es eine allgemeine Antwort auf diese Art von Frage gibt.
Nennen Sie mich Steve

@callmesteve: Ich weiß, was du meinst, aber dein letzter Satz sollte für jeden Programmierer wie Nägel über einer Kreidetafel klingen.
Wouter van Nifterick

1
Dies scheint die Frage nicht zu beantworten und liest sich eher als Kommentar oder Schimpfen.
Tas

-13

Inspiriert davon machte ich einen Schnelltest mit 60 Prozent der in den meisten Programmen benötigten allgemeinen Anweisungen.

Hier ist der C # -Code:

for (int i=0; i<1000; i++)
{
    StreamReader str = new StreamReader("file.csv");
    StreamWriter stw = new StreamWriter("examp.csv");
    string strL = "";
    while((strL = str.ReadLine()) != null)
    {
        ArrayList al = new ArrayList();
        string[] strline = strL.Split(',');
        al.AddRange(strline);
        foreach(string str1 in strline)
        {
            stw.Write(str1 + ",");
        }
        stw.Write("\n");
    }
    str.Close();
    stw.Close();
}

String-Array und Arraylist werden absichtlich verwendet, um diese Anweisungen einzuschließen.

Hier ist der C ++ - Code:

for (int i = 0; i<1000; i++)
{
    std::fstream file("file.csv", ios::in);
    if (!file.is_open())
    {
        std::cout << "File not found!\n";
        return 1;
    }

    ofstream myfile;
    myfile.open ("example.txt");
    std::string csvLine;

    while (std::getline(file, csvLine))
    {
        std::istringstream csvStream(csvLine);
        std::vector csvColumn;
        std::string csvElement;

        while( std::getline(csvStream, csvElement, ‘,’) )
        {
            csvColumn.push_back(csvElement);
        }

        for (std::vector::iterator j = csvColumn.begin(); j != csvColumn.end(); ++j)
        {
            myfile << *j << ", ";
        }

        csvColumn.clear();
        csvElement.clear();
        csvLine.clear();
        myfile << "\n";
    }
    myfile.close();
    file.close();
}

Die von mir verwendete Eingabedateigröße betrug 40 KB.

Und hier ist das Ergebnis -

  • C ++ - Code lief in 9 Sekunden.
  • C # Code: 4 Sekunden !!!

Oh, aber das war unter Linux ... mit C # unter Mono ... und C ++ mit g ++.

OK, das habe ich unter Windows - Visual Studio 2003 erhalten :

  • C # -Code lief in 9 Sekunden.
  • C ++ Code - schreckliche 370 Sekunden !!!

7
Sie verwenden dort unterschiedliche Datenstrukturen und Bibliothekscodes, obwohl "370 Sekunden" etwas Schreckliches anzeigt - Sie führen es nicht zufällig im Debugger aus, oder? Ich vermute, dass die Leistung der von Ihnen verwendeten CSV-Bibliothek interessanter ist als die Leistung der von Ihnen verwendeten Sprache. Ich würde die Verwendung eines Vektors in diesem Zusammenhang in Frage stellen und welche Optimierungen Sie verwendet haben. Darüber hinaus ist allgemein bekannt, dass iostreams (insbesondere "myfile << * j <<", ";") zumindest für einige gängige Implementierungen viel langsamer sind als andere Methoden zum Schreiben in die Datei.
Arafangion

6
Schließlich erledigen Sie mehr Arbeit in der C ++ - Version. (Warum löschen Sie die csvColumn, csvElement und csvLines?)
Arafangion

2
Bei jeder Iteration der while-Schleife werden ein std :: istream und ein std :: vector sowie ein std :: string zerstört und rekonstruiert. Der while-Körper verlässt bei jeder Iteration den Gültigkeitsbereich. Alle diese Variablen im while-Gültigkeitsbereich werden bei jeder Iteration zerstört und konstruiert.
Doug65536

1
Nach dem Aussehen Ihres C ++ - Codes versuchen Sie, von einer Datei in eine andere Datei zu kopieren. Anstatt die komplexen Wechselwirkungen zwischen Dateistreams, Zeichenfolgen, Vektoren und Zeichenfolgenströmen zu verwenden, hätten Sie den Eingabedateistream einfach in den Ausgabedateistream kopieren können. Dies hätte viel Zeit und Speicher gespart.
Zachary Kraus

2
Um Geschwindigkeitstests durchzuführen, testen Sie Dinge im Speicher, die nicht auf die Festplatten-E / A gelangen, und testen Sie nicht die neuesten SSDs, die für Ihre Leistungs-App vorgesehen sind. Da Computer ständig auf die Festplatte schreiben, auch wenn Sie die Tastatur nicht berühren.
user3800527
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.