Beim Anhören des StackOverflow-Podcasts taucht immer wieder auf, dass "echte Programmierer" in C schreiben und dass C so viel schneller ist, weil es "in der Nähe der Maschine" ist. Was ist das Besondere an C, das es ermöglicht, schneller als andere Sprachen zu sein, wenn man die frühere Behauptung für einen anderen Beitrag verlässt? Oder anders ausgedrückt: Was hindert andere Sprachen daran, in Binärdateien zu kompilieren, die genauso schnell wie C ausgeführt werden?
c
performance
Mike C.
quelle
quelle
Antworten:
Es gibt nicht viel Besonderes an C. Das ist einer der Gründe, warum es schnell ist.
Neuere Sprachen, die Garbage Collection , Dynamic Typing und andere Funktionen unterstützen, die es dem Programmierer erleichtern, Programme zu schreiben.
Der Haken ist, dass es zusätzlichen Verarbeitungsaufwand gibt, der die Leistung der Anwendung beeinträchtigt. C hat nichts davon, was bedeutet, dass es keinen Overhead gibt, aber das bedeutet, dass der Programmierer in der Lage sein muss, Speicher zuzuweisen und freizugeben, um Speicherlecks zu verhindern , und sich mit der statischen Typisierung von Variablen befassen muss.
Allerdings haben viele Sprachen und Plattformen wie Java (mit seiner Java Virtual Machine ) und .NET (mit seiner Common Language Runtime) im Laufe der Jahre die Leistung verbessert, mit Fortschritten wie der Just-in-Time-Kompilierung, aus der nativer Maschinencode erzeugt wird Bytecode für eine höhere Leistung.
quelle
Es gibt einen Kompromiss zwischen den C-Designern. Das heißt, sie haben die Entscheidung getroffen, Geschwindigkeit über Sicherheit zu stellen. C wird nicht
Wenn Sie in ein Array indizieren, sind in Java einige Methodenaufrufe in der virtuellen Maschine, gebundene Überprüfungen und andere Überprüfungen der Integrität erforderlich. Das ist gültig und absolut in Ordnung , weil es die Sicherheit dort erhöht, wo sie fällig ist. Aber in C werden selbst ziemlich triviale Dinge nicht in Sicherheit gebracht. Zum Beispiel benötigt C kein memcpy, um zu überprüfen, ob sich die zu kopierenden Regionen überlappen. Es ist nicht als Sprache zum Programmieren einer Big Business-Anwendung konzipiert.
Diese Entwurfsentscheidungen sind jedoch keine Fehler in der C-Sprache . Sie sind beabsichtigt, da sie es Compilern und Bibliotheksschreibern ermöglichen, jede Leistung aus dem Computer herauszuholen. Hier ist der Geist von C, wie das C Rationale- Dokument es erklärt:
quelle
Wenn Sie einen Monat damit verbringen, etwas in C zu erstellen, das in 0,05 Sekunden ausgeführt wird, und ich einen Tag damit verbringe, dasselbe in Java zu schreiben, und es in 0,10 Sekunden ausgeführt wird, ist C dann wirklich schneller?
Um Ihre Frage zu beantworten, läuft gut geschriebener C-Code im Allgemeinen schneller als gut geschriebener Code in anderen Sprachen, da ein Teil des Schreibens von C-Code "gut" manuelle Optimierungen auf maschinennaher Ebene umfasst.
Obwohl Compiler in der Tat sehr clever sind, sind sie noch nicht in der Lage, kreativ Code zu entwickeln, der mit handmassierten Algorithmen konkurriert (vorausgesetzt, die "Hände" gehören einem guten C-Programmierer).
Bearbeiten:
Viele Kommentare lauten wie folgt: "Ich schreibe in C und denke nicht über Optimierungen nach."
Aber um ein konkretes Beispiel aus diesem Beitrag zu nehmen :
In Delphi könnte ich folgendes schreiben:
und in CI schreiben Sie dies:
Aber wie viele Optimierungen gibt es in der C-Version? Wir treffen viele Entscheidungen über die Implementierung, an die ich in der Delphi-Version nicht denke. Wie wird ein String implementiert? In Delphi sehe ich es nicht. In C habe ich beschlossen, dass es ein Zeiger auf ein Array von ASCII-Ganzzahlen sein wird, die wir Zeichen nennen. In C testen wir nacheinander die Existenz von Charakteren. In Delphi benutze ich Pos.
Und das ist nur ein kleines Beispiel. In einem großen Programm muss ein C-Programmierer diese Art von Entscheidungen auf niedriger Ebene alle paar Codezeilen treffen. Es ergibt eine handgefertigte, handoptimierte ausführbare Datei.
quelle
Ich habe es noch nicht gesehen, also sage ich es: C ist tendenziell schneller, weil fast alles andere in C geschrieben ist .
Java basiert auf C, Python basiert auf C (oder Java oder .NET usw.), Perl usw. Das Betriebssystem ist in C geschrieben, die virtuellen Maschinen sind in C geschrieben, die Compiler sind in C geschrieben. Die Dolmetscher sind in C geschrieben. Einige Dinge sind immer noch in Assemblersprache geschrieben, was tendenziell noch schneller ist. Immer mehr Dinge werden in etwas anderem geschrieben, das selbst in C geschrieben ist.
Jede Anweisung, die Sie in anderen Sprachen schreiben (nicht in Assembly), wird normalerweise darunter als mehrere Anweisungen in C implementiert, die bis zum nativen Maschinencode kompiliert werden. Da diese anderen Sprachen in der Regel vorhanden sind, um einen höheren Abstraktionsgrad als C zu erzielen, konzentrieren sich die in C erforderlichen zusätzlichen Anweisungen in der Regel auf die Erhöhung der Sicherheit, die Erhöhung der Komplexität und die Bereitstellung der Fehlerbehandlung. Das sind oft gute Dinge, aber sie haben Kosten und ihre Namen sind Geschwindigkeit und Größe .
Persönlich habe ich in buchstäblich Dutzenden von Sprachen geschrieben, die den größten Teil des verfügbaren Spektrums abdecken, und ich persönlich habe die Magie gesucht, auf die Sie hinweisen:
Nach ein paar Jahren Recherche lautet meine Antwort Python (auf C). Vielleicht möchten Sie es sich ansehen. Übrigens können Sie auch von Python aus zu Assembly wechseln (mit geringfügiger Hilfe einer speziellen Bibliothek).
Andererseits kann schlechter Code in jeder Sprache geschrieben werden . Daher ist der C- (oder Assembly-) Code nicht automatisch schneller. Ebenso können einige Optimierungstricks Teile des übergeordneten Sprachcodes nahe an das Leistungsniveau von Raw C bringen. Bei den meisten Anwendungen verbringt Ihr Programm jedoch die meiste Zeit damit, auf Personen oder Hardware zu warten, sodass der Unterschied wirklich keine Rolle spielt.
Genießen.
quelle
Es gibt viele Fragen - meistens solche, für deren Beantwortung ich nicht qualifiziert bin. Aber für diesen letzten:
Mit einem Wort: Abstraktion.
C ist nur eine oder zwei Abstraktionsebenen von der Maschinensprache entfernt. Java und die .NET-Sprachen befinden sich mindestens drei Abstraktionsebenen vom Assembler entfernt. Bei Python und Ruby bin ich mir nicht sicher.
Je mehr Programmierspielzeug (komplexe Datentypen usw.) vorhanden ist, desto weiter sind Sie von der Maschinensprache entfernt und desto mehr Übersetzungen müssen durchgeführt werden.
Ich bin hier und da weg, aber das ist das Wesentliche.
Update ------- Es gibt einige gute Kommentare zu diesem Beitrag mit mehr Details.
quelle
Es ist nicht so sehr, dass C schnell ist, sondern dass das Kostenmodell von C transparent ist . Wenn ein C-Programm langsam ist, ist es auf offensichtliche Weise langsam: durch Ausführen vieler Anweisungen. Verglichen mit den Betriebskosten in C können Operationen auf hoher Ebene an Objekten (insbesondere Reflexion) oder Zeichenfolgen Kosten verursachen, die nicht offensichtlich sind.
Zwei Sprachen, die im Allgemeinen zu Binärdateien kompiliert werden, die genauso schnell wie C sind, sind Standard ML (mit dem MLton- Compiler) und Objective Caml . Wenn Sie sich das Benchmark-Spiel ansehen, werden Sie feststellen, dass die OCaml-Version für einige Benchmarks, wie z. B. Binärbäume, schneller als C ist. (Ich habe keine MLton-Einträge gefunden.) Aber nehmen Sie das Shootout nicht zu ernst. Es ist, wie es heißt, ein Spiel. Die Ergebnisse spiegeln oft wider, wie viel Aufwand die Leute in die Optimierung des Codes gesteckt haben.
quelle
C ist nicht immer schneller.
C ist langsamer als zum Beispiel Modern Fortran.
C ist für einige Dinge oft langsamer als Java. (Besonders nachdem der JIT-Compiler Ihren Code ausprobiert hat)
C lässt Zeiger-Aliasing zu, was bedeutet, dass einige gute Optimierungen nicht möglich sind. Insbesondere wenn Sie mehrere Ausführungseinheiten haben, führt dies zu Datenabrufstillständen. Ow.
Die Annahme, dass Zeigerarithmetik funktioniert, führt bei einigen CPU-Familien (insbesondere PIC!) Zu einer langsam aufgeblähten Leistung. Früher wurde die große Leistung bei segmentiertem x86 verwendet.
Grundsätzlich stinkt C, wenn Sie eine Vektoreinheit oder einen Parallelisierungscompiler erhalten, und das moderne Fortran läuft schneller.
C-Programmierer-Tricks wie Thunking (Ändern der ausführbaren Datei im laufenden Betrieb) führen zum Stillstand des CPU-Prefetch.
Verstehst du den Drift?
Und unser guter Freund, der x86, führt einen Befehlssatz aus, der heutzutage wenig mit der tatsächlichen CPU-Architektur zu tun hat. Schattenregister, Load-Store-Optimierer, alles in der CPU. C ist also nahe am virtuellen Metall. Das echte Metall, Intel lässt dich nicht sehen. (Historisch gesehen waren VLIW-CPUs ein bisschen pleite, vielleicht ist das gar nicht so schlecht.)
Wenn Sie in C auf einem Hochleistungs-DSP (möglicherweise einem TI-DSP?) Programmieren, muss der Compiler einige knifflige Aufgaben ausführen, um das C über mehrere parallele Ausführungseinheiten hinweg abzuwickeln. In diesem Fall befindet sich C nicht in der Nähe des Metalls, sondern in der Nähe des Compilers, wodurch die gesamte Programmoptimierung durchgeführt wird. Seltsam.
Und schließlich führen einige CPUs (www.ajile.com) Java-Bytecodes in der Hardware aus. C würde eine PITA auf dieser CPU verwenden.
quelle
Nichts. Moderne Sprachen wie Java oder .NET langs orientieren sich eher an der Produktivität der Programmierer als an der Leistung. Hardware ist heutzutage billig. Auch das Kompilieren zur Zwischendarstellung bietet viele Vorteile wie Sicherheit, Portabilität usw. .NET CLR kann unterschiedliche Hardware nutzen - zum Beispiel müssen Sie das Programm nicht manuell optimieren / neu kompilieren, um den SSE-Befehlssatz zu verwenden.
quelle
Die Hauptfaktoren sind, dass es sich um eine statisch typisierte Sprache handelt, die zu Maschinencode kompiliert wurde. Da es sich um eine einfache Sprache handelt, macht sie im Allgemeinen nichts, was Sie nicht sagen.
Dies sind einige andere Faktoren, die mir in den Sinn kommen.
Die meisten statisch typisierten Sprachen könnten jedoch genauso schnell oder schneller als C kompiliert werden, insbesondere wenn sie Annahmen treffen können, die C aufgrund von Zeiger-Aliasing usw. nicht kann.
quelle
Ich denke du hast vergessen, dass Assemblersprache auch eine Sprache ist :)
Aber im Ernst, C-Programme sind nur dann schneller, wenn der Programmierer weiß, was er tut. Sie können problemlos ein C-Programm schreiben, das langsamer ausgeführt wird als Programme, die in anderen Sprachen geschrieben wurden und denselben Job ausführen.
Der Grund, warum C schneller ist, liegt darin, dass es auf diese Weise entworfen wurde. Sie können damit viele "untergeordnete" Aufgaben ausführen, die dem Compiler helfen, den Code zu optimieren. Oder, sagen wir, Sie als Programmierer sind für die Optimierung des Codes verantwortlich. Aber es ist oft ziemlich knifflig und fehleranfällig.
Andere Sprachen, wie bereits andere, konzentrieren sich mehr auf die Produktivität des Programmierers. Es wird allgemein angenommen, dass die Programmierzeit viel teurer ist als die Maschinenzeit (selbst in den alten Tagen). Daher ist es sehr sinnvoll, die Zeit, die Programmierer für das Schreiben und Debuggen von Programmen aufwenden, anstelle der Laufzeit der Programme zu minimieren. Um dies zu tun, werden Sie ein wenig dafür opfern, was Sie tun können, um das Programm schneller zu machen, da viele Dinge automatisiert sind.
quelle
Zum größten Teil entspricht jeder C-Befehl nur sehr wenigen Assembler-Befehlen. Sie schreiben im Wesentlichen Maschinencode auf höherer Ebene, sodass Sie die Kontrolle über fast alles haben, was der Prozessor tut. Viele andere kompilierte Sprachen, wie z. B. C ++, enthalten viele einfach aussehende Anweisungen, die sich in viel mehr Code verwandeln können als Sie denken (virtuelle Funktionen, Kopierkonstruktoren usw.). Und interpretierte Sprachen wie Java oder Ruby haben eine andere Ebene Anweisungen, die Sie nie sehen - die virtuelle Maschine oder der Interpreter.
quelle
Ich weiß, dass viele Leute es auf langwierige Weise gesagt haben, aber:
quelle
C ++ ist im Durchschnitt schneller (wie ursprünglich eine Obermenge von C, obwohl es einige Unterschiede gibt). Für bestimmte Benchmarks gibt es jedoch häufig eine andere Sprache, die schneller ist.
https://benchmarksgame-team.pages.debian.net/benchmarksgame/
fannjuch-redux
war am schnellsten in Scalan-body
undfasta
waren schneller in Ada.spectral-norm
war am schnellsten in Fortran.reverse-complement
,mandelbrot
Undpidigits
waren am schnellsten in ATS.regex-dna
war am schnellsten in JavaScript.chameneou-redux
Am schnellsten war Java 7.thread-ring
war am schnellsten in Haskell.Die restlichen Benchmarks waren in C oder C ++ am schnellsten.
quelle
extern "C"
hat nichts damit zu tun, dass C ++ eine Obermenge von C. istsystem("bash script.sh");
für jedes Bash-Skript funktioniert, und daher ist C eine Obermenge von Bash.extern "C"
stellt die C-Verknüpfung in C ++ aufgrund von Namensmangel bereit. Während das Aufrufen von X als Obermenge von Y bedeutet, dass alles, was in Y ausgeführt werden kann, auch in X ausgeführt werden kann, was für C ++ nicht gilt. Es gibt einige Sprachkonstrukte, die in C gültig sind, aber nicht in C ++.bash
was ein verfügbares Befehlszeilenprogramm vorschreibt . Wenn dies der Fall wäre und enthalten würde, welche Version / Spezifikation von Bash unterstützt werden muss, würde ich es als Obermenge betrachten.struct foo { int: this; }; typedef float foo;
Viele dieser Antworten geben gültige Gründe dafür an, warum C schneller ist oder nicht (entweder im Allgemeinen oder in bestimmten Szenarien). Es ist nicht zu leugnen, dass:
Ungeachtet dessen ist mir noch etwas anderes aufgefallen, das meiner Meinung nach die Vergleichsleistung von C im Vergleich zu vielen anderen Sprachen stärker beeinflusst als jeder andere Faktor. Nämlich:
Andere Sprachen erleichtern häufig das Schreiben von Code, der langsamer ausgeführt wird. Oft wird es sogar durch die Designphilosophien der Sprache gefördert. Folgerung: Ein C-Programmierer schreibt eher Code, der keine unnötigen Operationen ausführt.
Stellen Sie sich als Beispiel ein einfaches Windows-Programm vor, in dem ein einzelnes Hauptfenster erstellt wird. Die AC-Version würde eine
WNDCLASS[EX]
Struktur füllen, an die übergeben würdeRegisterClass[Ex]
, dann aufrufenCreateWindow[Ex]
und eine Nachrichtenschleife eingeben. Es folgt ein stark vereinfachter und abgekürzter Code:Ein äquivalentes Programm in C # kann nur eine Codezeile sein:
Diese eine Codezeile bietet alle Funktionen, die fast 20 Zeilen C-Code bieten, und fügt einige Dinge hinzu, die wir ausgelassen haben, z. B. die Fehlerprüfung. Die reichhaltigere, umfassendere Bibliothek (im Vergleich zu den in einem typischen C-Projekt verwendeten) hat viel Arbeit für uns geleistet und uns Zeit gelassen, viel mehr Codefragmente zu schreiben, die für uns kurz aussehen, aber viele Schritte hinter die Kulissen beinhalten.
Aber eine umfangreiche Bibliothek, die einfaches und schnelles Aufblähen von Code ermöglicht, ist nicht wirklich mein Punkt. Mein Punkt wird deutlicher, wenn Sie untersuchen, was tatsächlich passiert, wenn unser kleiner Einzeiler tatsächlich ausgeführt wird. Aktivieren Sie zum Spaß manchmal den .NET -Quellzugriff in Visual Studio 2008 oder höher und gehen Sie in die einfache einzeilige Zeile oben. Eines der lustigen kleinen Juwelen, auf das Sie stoßen werden, ist dieser Kommentar im Getter für
Control.CreateParams
:Zehnmal . Die Information entspricht in etwa der Summe dessen , was in einer gespeichert ist
WNDCLASSEX
Struktur und was übergeben wirdCreateWindowEx
von den abgerufenControl
Klasse zehnmal , bevor es in einer gespeichert istWNDCLASSEX
Struktur und anRegisterClassEx
undCreateWindowEx
.Alles in allem beträgt die Anzahl der Befehle, die zur Ausführung dieser sehr grundlegenden Aufgabe ausgeführt werden, in C # 2–3 Größenordnungen mehr als in C. Ein Teil davon ist auf die Verwendung einer funktionsreichen Bibliothek zurückzuführen, die notwendigerweise verallgemeinert ist unser einfacher C-Code, der genau das tut, was wir brauchen und nichts weiter. Ein Teil davon ist jedoch auf die Tatsache zurückzuführen, dass sich die modularisierte, objektorientierte Natur von .NET Framework für viele Wiederholungen der Ausführung eignet, die häufig durch einen prozeduralen Ansatz vermieden werden.
Ich versuche nicht, C # oder das .NET-Framework auszuwählen. Ich sage auch nicht, dass Modularisierung, Generalisierung, Bibliotheks- / Sprachfunktionen, OOP usw. schlechte Dinge sind . Ich habe den größten Teil meiner Entwicklung in C, später in C ++ und zuletzt in C # durchgeführt. In ähnlicher Weise habe ich vor C hauptsächlich Montage verwendet. Und mit jedem Schritt "höher" meiner Sprache schreibe ich bessere, wartbarere und robustere Programme in kürzerer Zeit. Sie neigen jedoch dazu, etwas langsamer auszuführen.
quelle
Ich glaube nicht, dass irgendjemand die Tatsache erwähnt hat, dass C-Compiler viel mehr Aufwand betrieben haben als jeder andere Compiler, vielleicht mit Ausnahme von Java.
C ist aus vielen der bereits genannten Gründe äußerst optimierbar - mehr als fast jede andere Sprache. Wenn also andere Sprachcompiler den gleichen Aufwand betreiben, wird C wahrscheinlich immer noch die Nase vorn haben.
Ich denke, es gibt mindestens eine Kandidatensprache, die mit Aufwand besser optimiert werden könnte als C, und daher könnten wir Implementierungen sehen, die schnellere Binärdateien erzeugen. Ich denke an Digital Mars D, weil der Ersteller darauf geachtet hat, eine Sprache zu erstellen, die möglicherweise besser optimiert werden kann als C. Möglicherweise gibt es andere Sprachen, die diese Möglichkeit haben. Ich kann mir jedoch nicht vorstellen, dass eine Sprache Compiler mehr als nur ein paar Prozent schneller haben wird als die besten C-Compiler. Ich würde gerne falsch liegen.
Ich denke, die wirkliche "niedrig hängende Frucht" wird in Sprachen sein, die so gestaltet sind, dass sie für den Menschen EINFACH zu optimieren sind. Ein erfahrener Programmierer kann jede Sprache schneller machen - aber manchmal muss man lächerliche Dinge tun oder unnatürliche Konstrukte verwenden, um dies zu erreichen. Obwohl es immer mühsam sein wird, sollte eine gute Sprache relativ schnellen Code produzieren, ohne genau darüber nachdenken zu müssen, wie das Programm geschrieben ist.
Es ist auch wichtig (zumindest für mich), dass der Worst-Case-Code in der Regel schnell ist. Es gibt zahlreiche "Beweise" im Web, dass Java genauso schnell oder schneller als C ist, aber das basiert auf Beispielen für die Kirschernte. Ich bin kein großer Fan von C, aber ich weiß, dass ALLES, was ich in C schreibe, gut laufen wird. Mit Java wird es "wahrscheinlich" innerhalb von 15% der Geschwindigkeit laufen, normalerweise innerhalb von 25%, aber in einigen Fällen kann es weitaus schlimmer sein. Alle Fälle, in denen es genauso schnell oder innerhalb von ein paar Prozent ist, sind normalerweise darauf zurückzuführen, dass die meiste Zeit im Bibliothekscode verbracht wird, der ohnehin stark optimiert ist.
quelle
Dies ist eigentlich eine Art fortgesetzte Lüge. Zwar sind C-Programme häufig schneller, dies ist jedoch nicht immer der Fall, insbesondere wenn der C-Programmierer nicht sehr gut darin ist.
Ein großes Loch, das die Leute gerne vergessen, ist, wenn das Programm für eine Art von E / A blockieren muss, z. B. für Benutzereingaben in einem GUI-Programm. In diesen Fällen spielt es keine Rolle, welche Sprache Sie verwenden, da Sie durch die Geschwindigkeit, mit der Daten eingehen können, und nicht durch die Geschwindigkeit, mit der Sie sie verarbeiten können, eingeschränkt sind. In diesem Fall spielt es keine Rolle, ob Sie C, Java, C # oder sogar Perl verwenden. Sie können einfach nicht schneller gehen, als die Daten eingehen können.
Die andere wichtige Sache ist, dass die virtuelle Maschine durch die Verwendung der Garbage Collection und nicht der Verwendung geeigneter Zeiger eine Reihe von Optimierungen vornehmen kann, die in anderen Sprachen nicht verfügbar sind. Beispielsweise kann die JVM Objekte auf dem Heap verschieben, um ihn zu defragmentieren. Dies beschleunigt zukünftige Zuordnungen erheblich, da der nächste Index einfach verwendet werden kann, anstatt ihn in einer Tabelle nachzuschlagen. Moderne JVMs müssen den Speicher auch nicht freigeben. Stattdessen verschieben sie nur die lebenden Objekte, wenn sie GC durchführen, und der verbrauchte Speicher der toten Objekte wird im Wesentlichen kostenlos wiederhergestellt.
Dies bringt auch einen interessanten Punkt über C und noch mehr in C ++. Es gibt so etwas wie eine Designphilosophie: "Wenn Sie es nicht brauchen, zahlen Sie nicht dafür." Das Problem ist, dass Sie, wenn Sie es wollen, am Ende durch die Nase dafür bezahlen. Beispielsweise ist die vtable-Implementierung in Java in der Regel viel besser als C ++ - Implementierungen, sodass virtuelle Funktionsaufrufe viel schneller sind. Auf der anderen Seite haben Sie keine andere Wahl, als virtuelle Funktionen in Java zu verwenden, und sie kosten immer noch etwas, aber in Programmen, die viele virtuelle Funktionen verwenden, summieren sich die reduzierten Kosten.
quelle
Es geht weniger um die Sprache als um die Werkzeuge und Bibliotheken. Die verfügbaren Bibliotheken und Compiler für C sind viel älter als für neuere Sprachen. Sie könnten denken, dies würde sie langsamer machen, aber au contraire.
Diese Bibliotheken wurden zu einer Zeit geschrieben, als Rechenleistung und Speicher einen hohen Stellenwert hatten. Sie mussten sehr effizient geschrieben werden, um überhaupt arbeiten zu können. Entwickler von C-Compilern hatten auch lange Zeit, um an allen möglichen cleveren Optimierungen für verschiedene Prozessoren zu arbeiten. Die Reife und breite Akzeptanz von C verschafft anderen Sprachen des gleichen Alters einen deutlichen Vorteil. Es gibt C auch einen Geschwindigkeitsvorteil gegenüber neueren Tools, bei denen die Rohleistung nicht so stark betont wird wie bei C.
quelle
Der Mangel an Abstraktion macht C schneller. Wenn Sie eine Ausgabeanweisung schreiben, wissen Sie genau, was passiert. Wenn Sie eine Ausgabeanweisung in Java schreiben, wird sie in eine Klassendatei kompiliert, die dann auf einer virtuellen Maschine ausgeführt wird, die eine Abstraktionsschicht einführt. Das Fehlen objektorientierter Funktionen als Teil der Sprache erhöht auch die Geschwindigkeit, mit der weniger Code generiert wird. Wenn Sie C als objektorientierte Sprache verwenden, führen Sie die gesamte Codierung für Dinge wie Klassen, Inharitenz usw. durch. Dies bedeutet, dass Sie für jeden etwas verallgemeinern, das für die Menge an Code und die Leistungsschwäche, für die Sie nur schreiben müssen, ausreichend ist was Sie brauchen, um die Arbeit zu erledigen.
quelle
Erstaunlich zu sehen, dass der alte Mythos "C / C ++ muss schneller sein als Java, weil Java interpretiert wird" immer noch lebendig ist. Es gibt Artikel, die einige Jahre zurückreichen , sowie neuere , die mit Konzepten oder Messungen erklären, warum dies einfach nicht immer der Fall ist .
Aktuelle Implementierungen virtueller Maschinen (und übrigens nicht nur die JVM) können die während der Programmausführung gesammelten Informationen nutzen, um den Code während der Ausführung mithilfe verschiedener Techniken dynamisch zu optimieren:
und eine Vielzahl anderer Anpassungen, die darauf basieren, zu wissen, was der Code tatsächlich tut, und auf den tatsächlichen Merkmalen der Umgebung, in der er ausgeführt wird.
quelle
Der am schnellsten laufende Code wäre sorgfältig handgefertigter Maschinencode. Assembler wird fast genauso gut sein. Beide sind sehr niedrig und es erfordert viel Code, um Dinge zu tun. C liegt etwas über dem Assembler. Sie haben immer noch die Möglichkeit, Dinge auf einer sehr niedrigen Ebene in der tatsächlichen Maschine zu steuern, aber es gibt genug Abstraktion, um das Schreiben schneller und einfacher zu machen als Assembler. Andere Sprachen wie C # und JAVA sind noch abstrakter. Während Assembler und Maschinencode als Low-Level-Sprachen bezeichnet werden, werden C # und JAVA (und viele andere) als High-Level-Sprachen bezeichnet. C wird manchmal als Mittelsprache bezeichnet.
quelle
Nehmen Sie kein Wort dafür, sondern sehen Sie sich die Zerlegung für C und die Sprache Ihrer Wahl in einem leistungskritischen Teil Ihres Codes an. Ich denke, Sie können zur Laufzeit in Visual Studio einfach in das Demontagefenster schauen, um das zerlegte .Net zu sehen. Sollte möglich sein, wenn es für Java mit windbg schwierig ist, aber wenn Sie es mit .Net tun, wären viele der Probleme gleich.
Ich schreibe nicht gerne in C, wenn ich nicht muss, aber ich denke, dass viele der Behauptungen in diesen Antworten, die die Geschwindigkeit anderer Sprachen als C ankündigen, durch einfaches Zerlegen derselben Routine in C und aufgehoben werden können in der Sprache Ihrer Wahl auf höherer Ebene, insbesondere wenn viele Daten beteiligt sind, wie dies bei leistungskritischen Anwendungen üblich ist. Fortran kann eine Ausnahme in seinem Fachgebiet sein, weiß nicht. Ist es höher als C?
Beim ersten Vergleich von JITed-Code mit nativem Code wurden alle Fragen geklärt, ob .Net-Code vergleichbar mit C-Code ausgeführt werden kann. Die zusätzliche Abstraktionsebene und alle Sicherheitsüberprüfungen sind mit erheblichen Kosten verbunden. Die gleichen Kosten würden wahrscheinlich für Java anfallen, aber nehmen Sie nicht mein Wort und probieren Sie es an etwas aus, bei dem die Leistung entscheidend ist. (Weiß jemand genug über JITed Java, um eine kompilierte Prozedur im Speicher zu finden? Es sollte auf jeden Fall möglich sein)
quelle
1) Wie andere gesagt haben, tut C weniger für Sie. Keine Initialisierungsvariablen, keine Überprüfung der Array-Grenzen, keine Speicherverwaltung usw. Diese Funktionen in anderen Sprachen kosten Speicher und CPU-Zyklen, die C nicht ausgibt.
2) Antworten, die besagen, dass C weniger abstrahiert und daher schneller ist, sind meiner Meinung nach nur halb richtig. Wenn Sie einen "ausreichend fortgeschrittenen Compiler" für Sprache X hätten, könnte sich Sprache X der Geschwindigkeit von C annähern oder dieser entsprechen. Der Unterschied zu C besteht darin, dass sie so offensichtlich abgebildet wird (wenn Sie einen Architekturkurs belegt haben) und direkt zur Assemblersprache, die selbst ein naiver Compiler anständig machen kann. Für etwas wie Python benötigen Sie einen sehr fortgeschrittenen Compiler, um die wahrscheinlichen Objekttypen vorherzusagen und Maschinencode im laufenden Betrieb zu generieren. Die Semantik von C ist so einfach, dass ein einfacher Compiler dies gut kann.
quelle
In den guten alten Tagen gab es nur zwei Arten von Sprachen: kompiliert und interpretiert.
Kompilierte Sprachen verwendeten einen "Compiler", um die Sprachsyntax zu lesen und in identischen Assembler-Code umzuwandeln, der nicht nur direkt auf der CPU ausgeführt werden konnte. Interpretierte Sprachen verwendeten einige verschiedene Schemata, aber im Wesentlichen wurde die Sprachsyntax in eine Zwischenform konvertiert und dann in einem "Interpreter" ausgeführt, einer Umgebung zum Ausführen des Codes.
In gewisser Weise gab es also eine andere "Schicht" - den Interpreter - zwischen dem Code und der Maschine. Und wie immer bei einem Computer bedeutet mehr, dass mehr Ressourcen verwendet werden. Dolmetscher waren langsamer, weil sie mehr Operationen durchführen mussten.
In jüngerer Zeit haben wir mehr hybride Sprachen wie Java gesehen, die sowohl einen Compiler als auch einen Interpreter verwenden, damit sie funktionieren. Es ist kompliziert, aber eine JVM ist schneller, ausgefeilter und viel optimierter als die alten Interpreter, sodass sich die Leistung (im Laufe der Zeit) viel besser ändert, wenn sie nur direkt kompiliertem Code entspricht. Natürlich haben die neueren Compiler auch ausgefallenere Optimierungstricks, sodass sie tendenziell viel besseren Code generieren als früher. Aber die meisten Optimierungen machen meistens (wenn auch nicht immer) einen Kompromiss, so dass sie nicht immer unter allen Umständen schneller sind. Wie alles andere ist auch nichts kostenlos, daher müssen sich die Optimierer von irgendwoher rühmen (obwohl sie häufig CPU zur Kompilierungszeit verwenden, um Laufzeit-CPU zu sparen).
Zurück zu C, es ist eine einfache Sprache, die zu einer ziemlich optimierten Assembly kompiliert und dann direkt auf dem Zielcomputer ausgeführt werden kann. Wenn Sie in C eine Ganzzahl inkrementieren, ist es mehr als wahrscheinlich, dass es sich nur um einen Assembler-Schritt in der CPU handelt. In Java kann dies jedoch viel mehr sein (und auch ein bisschen Garbage Collection enthalten: -) C bietet Ihnen eine Abstraktion, die viel näher an der Maschine liegt (Assembler ist am nächsten), aber Sie müssen am Ende viel mehr Arbeit leisten, um sie zum Laufen zu bringen, und sie ist nicht so geschützt, einfach zu bedienen oder fehlerfreundlich. Die meisten anderen Sprachen bieten Ihnen eine höhere Abstraktion und kümmern sich um mehr der zugrunde liegenden Details für Sie. Im Austausch für ihre erweiterten Funktionen benötigen sie jedoch mehr Ressourcen, um ausgeführt zu werden. Wenn Sie einige Lösungen verallgemeinern, müssen Sie mit einem breiteren Spektrum von Computern umgehen.
Paul.
quelle
++i
könnte zu "add [ebp - 8], 1" kompiliert werden. Um nicht zu sagen, dass das Abrufen, Inkrementieren und Speichern nicht immer noch stattfindet, aber dies wird von der CPU erledigt und ist nur eine Anweisung, wie Paul sagte.Abgesehen von fortschrittlichen Optimierungstechniken wie Hot-Spot-Optimierung , vorkompilierten Metaalgorithmen und verschiedenen Formen der Parallelität korreliert die grundlegende Geschwindigkeit einer Sprache stark mit der impliziten Komplexität hinter den Kulissen, die zur Unterstützung der üblichen Vorgänge erforderlich ist innerhalb der inneren Schleifen angegeben werden .
Am offensichtlichsten ist möglicherweise die Gültigkeitsprüfung indirekter Speicherreferenzen - beispielsweise das Überprüfen von Zeigern auf
null
und das Überprüfen von Indizes anhand von Arraygrenzen. Die meisten Hochsprachen führen diese Überprüfungen implizit durch, C jedoch nicht. Dies ist jedoch nicht unbedingt eine grundlegende Einschränkung dieser anderen Sprachen - ein ausreichend geschickter Compiler kann diese Überprüfungen möglicherweise durch irgendeine Form von schleifeninvarianter Codebewegung aus den inneren Schleifen eines Algorithmus entfernen .Der grundlegendere Vorteil von C (und in ähnlichem Maße das eng verwandte C ++) ist die starke Abhängigkeit von der stapelbasierten Speicherzuweisung , die für Zuweisung, Freigabe und Zugriff von Natur aus schnell ist . In C (und C ++) kann der primäre Aufrufstapel zur Zuweisung von Grundelementen, Arrays und Aggregaten (
struct
/class
) verwendet werden.Während C die Möglichkeit bietet, Speicher beliebiger Größe und Lebensdauer dynamisch zuzuweisen (unter Verwendung des sogenannten "Heaps"), wird dies standardmäßig vermieden (stattdessen wird der Stapel verwendet).
Interessanterweise ist es manchmal möglich, die C-Speicherzuweisungsstrategie in den Laufzeitumgebungen anderer Programmiersprachen zu replizieren. Dies wurde von asm.js demonstriert , mit dem in C oder C ++ geschriebener Code in eine Teilmenge von JavaScript übersetzt und sicher in einer Webbrowser-Umgebung ausgeführt werden kann - mit nahezu nativer Geschwindigkeit.
Abgesehen davon ist ein weiterer Bereich, in dem C und C ++ die meisten anderen Sprachen hinsichtlich der Geschwindigkeit übertreffen, die Möglichkeit, sich nahtlos in native Maschinenbefehlssätze zu integrieren. Ein bemerkenswertes Beispiel hierfür ist die (compiler- und plattformabhängige) Verfügbarkeit von SIMD-Intrinsics, die die Konstruktion benutzerdefinierter Algorithmen unterstützen, die die mittlerweile nahezu allgegenwärtige Parallelverarbeitungshardware nutzen - und gleichzeitig die von der Sprache bereitgestellten Datenzuordnungsabstraktionen verwenden (niedriger) Die Registerzuordnung auf der Ebene wird vom Compiler verwaltet.
quelle
Ich habe eine Antwort auf den Link gefunden, warum einige Sprachen schneller und einige langsamer sind. Ich hoffe, dies wird mehr darüber klären, warum C oder C ++ schneller als andere ist. Es gibt auch einige andere Sprachen, die schneller als C sind, aber wir können nicht benutze sie alle. Einige Erklärungen -
Einer der Hauptgründe, warum Fortran wichtig bleibt, ist seine Schnelligkeit: In Fortran geschriebene Routinen zur Zahlenverarbeitung sind in der Regel schneller als in den meisten anderen Sprachen geschriebene Routinen. Die Sprachen, die in diesem Bereich mit Fortran konkurrieren - C und C ++ - werden verwendet, weil sie mit dieser Leistung konkurrieren.
Dies wirft die Frage auf: Warum? Was macht C ++ und Fortran so schnell und warum übertreffen sie andere beliebte Sprachen wie Java oder Python?
Interpretieren versus Kompilieren Es gibt viele Möglichkeiten, Programmiersprachen zu kategorisieren und zu definieren, je nachdem, welchen Programmierstil sie fördern und welche Funktionen sie bieten. Bei der Betrachtung der Leistung besteht der größte Unterschied zwischen interpretierten und kompilierten Sprachen.
Die Kluft ist nicht schwer; Vielmehr gibt es ein Spektrum. An einem Ende haben wir traditionelle kompilierte Sprachen, eine Gruppe, die Fortran, C und C ++ umfasst. In diesen Sprachen gibt es eine diskrete Kompilierungsphase, die den Quellcode eines Programms in eine ausführbare Form übersetzt, die der Prozessor verwenden kann.
Dieser Kompilierungsprozess besteht aus mehreren Schritten. Der Quellcode wird analysiert und analysiert. An dieser Stelle können grundlegende Codierungsfehler wie Tippfehler und Rechtschreibfehler erkannt werden. Der analysierte Code wird verwendet, um eine speicherinterne Darstellung zu generieren, mit der auch Fehler erkannt werden können - diesmal semantische Fehler wie das Aufrufen nicht vorhandener Funktionen oder der Versuch, arithmetische Operationen für Textzeichenfolgen auszuführen.
Diese speicherinterne Darstellung wird dann verwendet, um einen Codegenerator anzutreiben, der Teil, der ausführbaren Code erzeugt. Die Codeoptimierung zur Verbesserung der Leistung des generierten Codes wird zu verschiedenen Zeitpunkten innerhalb dieses Prozesses durchgeführt: Optimierungen auf hoher Ebene können für die Codedarstellung durchgeführt werden, und Optimierungen auf niedrigerer Ebene werden für die Ausgabe des Codegenerators verwendet.
Die eigentliche Ausführung des Codes erfolgt später. Der gesamte Kompilierungsprozess wird einfach verwendet, um etwas zu erstellen, das ausgeführt werden kann.
Am anderen Ende haben wir Dolmetscher. Die Interpreter enthalten eine Parsing-Phase, die der des Compilers ähnelt. Diese wird jedoch verwendet, um die direkte Ausführung zu steuern, wobei das Programm sofort ausgeführt wird.
Der einfachste Interpreter enthält ausführbaren Code, der den verschiedenen von der Sprache unterstützten Funktionen entspricht. Er verfügt also über Funktionen zum Hinzufügen von Zahlen, zum Verknüpfen von Zeichenfolgen und zu allen anderen Funktionen einer bestimmten Sprache. Beim Parsen des Codes wird die entsprechende Funktion nachgeschlagen und ausgeführt. Im Programm erstellte Variablen werden in einer Art Nachschlagetabelle gespeichert, die ihre Namen ihren Daten zuordnet.
Das extremste Beispiel für den Interpreter-Stil ist eine Batch-Datei oder ein Shell-Skript. In diesen Sprachen ist der ausführbare Code oft nicht einmal in den Interpreter selbst integriert, sondern in separate, eigenständige Programme.
Warum wirkt sich dies auf die Leistung aus? Im Allgemeinen verringert jede Indirektionsebene die Leistung. Der schnellste Weg, zwei Zahlen hinzuzufügen, besteht beispielsweise darin, beide Zahlen in Registern im Prozessor zu haben und den Befehl add des Prozessors zu verwenden. Das können kompilierte Programme. Sie können Variablen in Register einfügen und Prozessoranweisungen nutzen. In interpretierten Programmen erfordert dieselbe Addition möglicherweise zwei Suchvorgänge in einer Variablentabelle, um die hinzuzufügenden Werte abzurufen, und ruft dann eine Funktion auf, um die Addition durchzuführen. Diese Funktion verwendet möglicherweise denselben Prozessorbefehl wie das kompilierte Programm, um die eigentliche Addition durchzuführen, aber die zusätzliche Arbeit, bevor der Befehl tatsächlich verwendet werden kann, verlangsamt die Arbeit.
Wenn Sie mehr wissen möchten, überprüfen Sie bitte die Quelle
quelle
Einige C ++ - Algorithmen sind schneller als C, und einige Implementierungen von Algorithmen oder Entwurfsmustern in anderen Sprachen können schneller als C sein.
Wenn Leute sagen, dass C schnell ist und dann über eine andere Sprache sprechen, verwenden sie im Allgemeinen die Leistung von C als Benchmark.
quelle
Mit modernen optimierenden Compilern ist es höchst unwahrscheinlich, dass ein reines C-Programm, wenn überhaupt, viel schneller als kompilierter .net-Code ist. Mit der Produktivitätssteigerung, die Frameworks wie .net dem Entwickler bieten, können Sie Dinge an einem Tag erledigen, der in regulären C Wochen oder Monate gedauert hat. In Verbindung mit den günstigen Hardwarekosten im Vergleich zum Gehalt eines Entwicklers ist das Schreiben einfach viel billiger das Zeug in einer Hochsprache und werfen Hardware auf jede Langsamkeit.
Der Grund, warum Jeff und Joel davon sprechen, dass C die "echte Programmiersprache" ist, liegt darin, dass C kein Händchen hält. Sie müssen Ihr eigenes Gedächtnis zuweisen, dieses Gedächtnis freigeben, Ihre eigenen Grenzüberprüfungen durchführen usw. Es gibt so etwas nicht als neues Objekt (); Es gibt keine Garbage Collection, Klassen, OOP, Entity Frameworks, LINQ, Eigenschaften, Attribute, Felder oder ähnliches. Sie müssen Dinge wie Zeigerarithmetik und das Dereferenzieren eines Zeigers kennen. Und im Übrigen wissen und verstehen, was ein Zeiger ist. Sie müssen wissen, was ein Stapelrahmen ist und was der Befehlszeiger ist. Sie müssen das Speichermodell der CPU-Architektur kennen, an der Sie arbeiten. Es gibt viel implizites Verständnis der Architektur eines Mikrocomputers (normalerweise derMikrocomputer, an dem Sie arbeiten) beim Programmieren in C, der einfach nicht vorhanden oder notwendig ist, wenn Sie in etwas wie C # oder Java programmieren. Alle diese Informationen wurden in den Compiler- (oder VM-) Programmierer geladen.
quelle
Es ist der Unterschied zwischen automatischen und manuellen, übergeordneten Sprachen sind Abstraktionen, die somit automatisiert werden. C / C ++ werden manuell gesteuert und gehandhabt, selbst Fehlerprüfcode ist manchmal eine manuelle Arbeit.
C und C ++ sind ebenfalls kompilierte Sprachen, was bedeutet, dass nichts davon überall im Geschäft läuft. Diese Sprachen müssen für die Hardware, mit der Sie arbeiten, genau abgestimmt werden, um eine zusätzliche Ebene von Gotcha hinzuzufügen. Dies ist jedoch etwas beunruhigend, da C / C ++ - Compiler auf allen Plattformen immer häufiger eingesetzt werden. Sie können plattformübergreifende Kompilierungen durchführen. Es ist immer noch nicht überall eine Situation, in der Sie Compiler A grundsätzlich anweisen, gegen Compiler B denselben Code mit unterschiedlicher Architektur zu kompilieren.
Unter dem Strich sollen C-Sprachen nicht leicht zu verstehen oder zu begründen sein, weshalb sie auch als Systemsprachen bezeichnet werden. Sie kamen vor all diesem hochrangigen Abstraktionsquatsch heraus. Aus diesem Grund werden sie auch nicht für die Front-End-Webprogrammierung verwendet. Sie sind einfach nicht für die Aufgabe geeignet, sie wollen komplexe Probleme lösen, die mit herkömmlichen Sprachwerkzeugen nicht gelöst werden können.
Aus diesem Grund gibt es verrückte Dinge wie (Mikroarchitekturen, Treiber, Quantenphysik, AAA-Spiele, Betriebssysteme), für die C und C ++ einfach gut geeignet sind. Geschwindigkeit und Zahlenkalkulation sind die Hauptbereiche.
quelle
C ist schnell, weil es eine nativ kompilierte Sprache auf niedriger Ebene ist. Aber C ist nicht der schnellste. Der rekursive Fibonacci-Benchmark zeigt, dass Rust, Crystal und Nim schneller sein können.
quelle
Es gibt viele Gründe, darunter:
quelle