C # vs C - Großer Leistungsunterschied


94

Ich finde massive Leistungsunterschiede zwischen ähnlichem Code in C anc C #.

Der C-Code lautet:

#include <stdio.h>
#include <time.h>
#include <math.h>

main()
{
    int i;
    double root;

    clock_t start = clock();
    for (i = 0 ; i <= 100000000; i++){
        root = sqrt(i);
    }
    printf("Time elapsed: %f\n", ((double)clock() - start) / CLOCKS_PER_SEC);   

}

Und die C # (Konsolen-App) ist:

using System;
using System.Collections.Generic;
using System.Text;

namespace ConsoleApplication2
{
    class Program
    {
        static void Main(string[] args)
        {
            DateTime startTime = DateTime.Now;
            double root;
            for (int i = 0; i <= 100000000; i++)
            {
                root = Math.Sqrt(i);
            }
            TimeSpan runTime = DateTime.Now - startTime;
            Console.WriteLine("Time elapsed: " + Convert.ToString(runTime.TotalMilliseconds/1000));
        }
    }
}

Mit dem obigen Code wird das C # in 0,328125 Sekunden (Release-Version) abgeschlossen und das C benötigt 11,14 Sekunden, um ausgeführt zu werden.

Das c wird mit mingw zu einer ausführbaren Windows-Datei kompiliert.

Ich war immer davon ausgegangen, dass C / C ++ schneller oder zumindest mit C # .net vergleichbar ist. Was genau bewirkt, dass das C über 30-mal langsamer läuft?

BEARBEITEN: Es scheint, dass der C # -Optimierer den Stamm entfernt hat, da er nicht verwendet wurde. Ich habe die Root-Zuordnung in root + = geändert und die Summe am Ende ausgedruckt. Ich habe das C auch mit cl.exe kompiliert, wobei das Flag / O2 für maximale Geschwindigkeit gesetzt ist.

Die Ergebnisse sind jetzt: 3,75 Sekunden für den C 2,61 Sekunden für den C #

Das C dauert noch länger, aber das ist akzeptabel


18
Ich würde vorschlagen, dass Sie eine StopWatch anstelle einer DateTime verwenden.
Alex Fort

2
Welche Compiler-Flags? Werden beide mit aktivierten Optimierungen kompiliert?
Jalf

2
Was ist, wenn Sie -ffast-math mit dem C ++ - Compiler verwenden?
Dan McClain

10
Was für eine faszinierende Frage!
Robert S.

4
Möglicherweise ist die C sqrt-Funktion in C # nicht so gut. Dann wäre es kein Problem mit C, sondern mit der daran angehängten Bibliothek. Versuchen Sie einige Berechnungen ohne mathematische Funktionen.
Klew

Antworten:


61

Da Sie niemals 'root' verwenden, hat der Compiler möglicherweise den Aufruf entfernt, um Ihre Methode zu optimieren.

Sie könnten versuchen, die Quadratwurzelwerte in einem Akkumulator zu akkumulieren, sie am Ende der Methode auszudrucken und zu sehen, was los ist.

Bearbeiten: siehe Jalfs Antwort unten


1
Ein kleines Experimentieren legt nahe, dass dies nicht der Fall ist. Der Code für die Schleife wird generiert, obwohl die Laufzeit möglicherweise intelligent genug ist, um sie zu überspringen. Selbst
Dana

3
Es scheint, dass das Problem am anderen Ende liegt. C # verhält sich in allen Fällen angemessen. Sein C-Code wird anscheinend ohne Optimierungen kompiliert
Jalf

2
Vielen von Ihnen fehlt hier der Punkt. Ich habe viele ähnliche Fälle gelesen, in denen c # c / c ++ übertrifft und die Widerlegung immer darin besteht, eine Optimierung auf Expertenebene anzuwenden. 99% der Programmierer haben nicht das Wissen, solche Optimierungstechniken zu verwenden, um ihren Code etwas schneller als den c # -Code laufen zu lassen. Anwendungsfälle für für c / c ++ werden enger.

167

Sie müssen Debug-Builds vergleichen. Ich habe gerade Ihren C-Code kompiliert und bekommen

Time elapsed: 0.000000

Wenn Sie keine Optimierungen aktivieren, ist jedes Benchmarking, das Sie durchführen, völlig wertlos. (Und wenn Sie Optimierungen aktivieren, wird die Schleife wegoptimiert. Daher ist auch Ihr Benchmarking-Code fehlerhaft. Sie müssen ihn zwingen, die Schleife auszuführen, normalerweise indem Sie das Ergebnis oder ähnliches zusammenfassen und am Ende ausdrucken.)

Es scheint, dass Sie im Grunde genommen messen, "welcher Compiler den meisten Debugging-Overhead einfügt". Und es stellt sich heraus, dass die Antwort C ist. Aber das sagt uns nicht, welches Programm am schnellsten ist. Denn wenn Sie Geschwindigkeit wollen, aktivieren Sie Optimierungen.

Übrigens sparen Sie sich auf lange Sicht viele Kopfschmerzen, wenn Sie die Vorstellung aufgeben, dass Sprachen "schneller" sind als die anderen. C # hat nicht mehr Geschwindigkeit als Englisch.

Es gibt bestimmte Dinge in der C-Sprache, die selbst in einem naiven, nicht optimierenden Compiler effizient wären, und es gibt andere, die sich stark auf einen Compiler verlassen, um alles weg zu optimieren. Und das gilt natürlich auch für C # oder eine andere Sprache.

Die Ausführungsgeschwindigkeit wird bestimmt durch:

  • die Plattform, auf der Sie ausgeführt werden (Betriebssystem, Hardware, andere auf dem System ausgeführte Software)
  • der Compiler
  • Ihr Quellcode

Ein guter C # -Compiler liefert effizienten Code. Ein fehlerhafter C-Compiler generiert langsamen Code. Was ist mit einem C-Compiler, der C # -Code generiert hat, den Sie dann über einen C # -Compiler ausführen können? Wie schnell würde das laufen? Sprachen haben keine Geschwindigkeit. Ihr Code tut es.



18
Gute Antwort, aber ich bin nicht einverstanden mit der Sprachgeschwindigkeit, zumindest in Analogie: Es wurde festgestellt, dass Welsch aufgrund der hohen Häufigkeit langer Vokale eine langsamere Sprache ist als die meisten anderen. Außerdem erinnern sich Menschen besser an Wörter (und Wortlisten), wenn sie schneller zu sagen sind. web.missouri.edu/~cowann/docs/articles/before%201993/… en.wikipedia.org/wiki/Vowel_length en.wikipedia.org/wiki/Welsh_language
Ausnahmefehler

1
Nicht , dass hängt davon ab , was Sie sagen , in Welsch obwohl? Ich finde es unwahrscheinlich, dass alles langsamer ist.
Jalf

5
++ Hey Leute, lasst euch hier nicht ablenken. Wenn dasselbe Programm in einer Sprache schneller ausgeführt wird als in einer anderen, liegt dies daran, dass ein anderer Assemblycode generiert wird. In diesem speziellen Beispiel werden 99% oder mehr der Zeit in den Floating-Modus verschoben i, und sqrtgenau das wird gemessen.
Mike Dunlavey

116

Ich werde mich kurz fassen, es ist bereits als beantwortet markiert. C # hat den großen Vorteil, ein gut definiertes Gleitkommamodell zu haben. Dies entspricht zufällig dem nativen Betriebsmodus des FPU- und SSE-Befehlssatzes auf x86- und x64-Prozessoren. Kein Zufall da. Der JITter kompiliert Math.Sqrt () mit einigen Inline-Anweisungen.

Native C / C ++ ist mit jahrelanger Abwärtskompatibilität ausgestattet. Die Optionen / fp: präzise, ​​/ fp: schnell und / fp: strenge Kompilierung sind am sichtbarsten. Dementsprechend muss eine CRT-Funktion aufgerufen werden, die sqrt () implementiert und die ausgewählten Gleitkommaoptionen überprüft, um das Ergebnis anzupassen. Das ist langsam.


66
Dies ist eine seltsame Überzeugung unter C ++ - Programmierern. Sie scheinen zu glauben, dass der von C # generierte Maschinencode sich irgendwie von dem von einem nativen Compiler generierten Maschinencode unterscheidet. Es gibt nur eine Art. Unabhängig davon, welchen gcc-Compiler-Switch Sie verwenden oder welche Inline-Assembly Sie schreiben, gibt es immer noch nur einen FSQRT-Befehl. Es ist nicht immer schneller, weil eine Muttersprache es generiert hat, die CPU ist das egal.
Hans Passant

16
Das ist es, was das Pre-Jitting mit ngen.exe löst. Wir sprechen von C #, nicht von Java.
Hans Passant

20
@ user877329 - wirklich? Beeindruckend.
Andras Zoltan

7
Nein, der x64-Jitter verwendet SSE. Math.Sqrt () wird in die Anweisung sqrtsd-Maschinencode übersetzt.
Hans Passant

6
Obwohl es technisch gesehen kein Unterschied zwischen den Sprachen ist, führt der .net JITter im Vergleich zu einem typischen C / C ++ - Compiler nur begrenzte Optimierungen durch. Eine der größten Einschränkungen ist die mangelnde SIMD-Unterstützung, wodurch der Code häufig um das Vierfache langsamer wird. Nicht viele Eigenheiten aufzudecken, kann ebenfalls ein großer Fehler sein, aber das hängt sehr davon ab, was Sie tun.
CodesInChaos

57

Ich bin ein C ++ - und ein C # -Entwickler. Ich habe seit der ersten Beta des .NET Frameworks C # -Anwendungen entwickelt und mehr als 20 Jahre Erfahrung in der Entwicklung von C ++ - Anwendungen. Erstens wird C # -Code NIEMALS schneller sein als eine C ++ - Anwendung, aber ich werde nicht lange auf verwalteten Code, seine Funktionsweise, die Inter-Op-Schicht, interne Speicherverwaltungsschichten, das dynamische Typsystem und den Garbage Collector eingehen. Lassen Sie mich dennoch weiter sagen, dass die hier aufgeführten Benchmarks alle zu FALSCHEN Ergebnissen führen.

Lassen Sie mich erklären: Das erste, was wir berücksichtigen müssen, ist der JIT-Compiler für C # (.NET Framework 4). Jetzt erzeugt die JIT nativen Code für die CPU unter Verwendung verschiedener Optimierungsalgorithmen (die tendenziell aggressiver sind als das mit Visual Studio gelieferte Standard-C ++ - Optimierungsprogramm), und der vom .NET JIT-Compiler verwendete Befehlssatz spiegelt die tatsächliche CPU genauer wider Auf der Maschine könnten bestimmte Ersetzungen im Maschinencode vorgenommen werden, um Taktzyklen zu reduzieren und die Trefferquote im CPU-Pipeline-Cache zu verbessern und weitere Hyper-Threading-Optimierungen wie die Neuordnung von Befehlen und Verbesserungen in Bezug auf die Verzweigungsvorhersage zu erzielen.

Dies bedeutet, dass Ihre C ++ - Anwendung möglicherweise langsamer als die entsprechende C # - oder .NET-basierte Anwendung ausgeführt wird, wenn Sie Ihre C ++ - Anwendung nicht mit den richtigen Pararmetern für den RELEASE-Build kompilieren (nicht für den DEBUG-Build). Stellen Sie beim Angeben der Projekteigenschaften in Ihrer C ++ - Anwendung sicher, dass Sie "vollständige Optimierung" und "schnellen Code bevorzugen" aktivieren. Wenn Sie einen 64-Bit-Computer haben, MÜSSEN Sie angeben, dass x64 als Zielplattform generiert werden soll. Andernfalls wird Ihr Code über eine Konvertierungsunterschicht (WOW64) ausgeführt, wodurch die Leistung erheblich verringert wird.

Sobald Sie die richtigen Optimierungen im Compiler durchgeführt haben, erhalte ich 0,72 Sekunden für die C ++ - Anwendung und 1,16 Sekunden für die C # -Anwendung (beide im Release-Build). Da die C # -Anwendung sehr einfach ist und den in der Schleife verwendeten Speicher auf dem Stapel und nicht auf dem Heap zuweist, ist sie tatsächlich viel leistungsfähiger als eine echte Anwendung, die an Objekten, umfangreichen Berechnungen und größeren Datenmengen beteiligt ist. Die angegebenen Zahlen sind also optimistische Zahlen, die auf C # und das .NET-Framework ausgerichtet sind. Trotz dieser Tendenz ist die C ++ - Anwendung in etwas mehr als der Hälfte der Zeit fertig als die entsprechende C # -Anwendung. Beachten Sie, dass der von mir verwendete Microsoft C ++ - Compiler nicht über die richtige Pipeline- und Hyperthreading-Optimierung verfügte (Verwenden von WinDBG zum Anzeigen der Montageanweisungen).

Wenn wir nun den Intel-Compiler verwenden (der übrigens ein Branchengeheimnis für die Generierung von Hochleistungsanwendungen auf AMD / Intel-Prozessoren ist), wird derselbe Code für die ausführbare C ++ - Datei in 0,54 Sekunden ausgeführt, für Microsoft Visual Studio 2010 in 0,72 Sekunden Am Ende sind die Endergebnisse für C ++ 0,44 Sekunden und für C # 1,16 Sekunden. Der vom .NET JIT-Compiler erzeugte Code dauert also 214% länger als die ausführbare C ++ - Datei. Die meiste Zeit in den .54 Sekunden wurde damit verbracht, die Zeit vom System zu erhalten und nicht innerhalb der Schleife selbst!

Was in der Statistik ebenfalls fehlt, sind die Start- und Bereinigungszeiten, die nicht in den Timings enthalten sind. C # -Anwendungen verbringen in der Regel viel mehr Zeit mit dem Starten und Beenden als C ++ - Anwendungen. Der Grund dafür ist kompliziert und hängt mit den Validierungsroutinen für den .NET-Laufzeitcode und dem Speicherverwaltungssubsystem zusammen, das zu Beginn (und folglich am Ende) des Programms viel Arbeit leistet, um die Speicherzuordnungen und den Müll zu optimieren Kollektor.

Bei der Messung der Leistung von C ++ und .NET IL ist es wichtig, den Assemblycode zu überprüfen, um sicherzustellen, dass ALLE Berechnungen vorhanden sind. Was ich gefunden habe, ist, dass ohne zusätzlichen Code in C # der größte Teil des Codes in den obigen Beispielen tatsächlich aus der Binärdatei entfernt wurde. Dies war auch bei C ++ der Fall, als Sie einen aggressiveren Optimierer wie den mit dem Intel C ++ - Compiler gelieferten verwendeten. Die Ergebnisse, die ich oben angegeben habe, sind zu 100% korrekt und werden auf Baugruppenebene validiert.

Das Hauptproblem bei vielen Foren im Internet ist, dass viele Neulinge Microsoft-Marketingpropaganda hören, ohne die Technologie zu verstehen, und falsche Behauptungen aufstellen, dass C # schneller als C ++ ist. Die Behauptung ist, dass C # theoretisch schneller als C ++ ist, weil der JIT-Compiler den Code für die CPU optimieren kann. Das Problem bei dieser Theorie ist, dass im .NET Framework viele Installationen vorhanden sind, die die Leistung verlangsamen. Sanitär, das in C ++ - Anwendung nicht vorhanden ist. Darüber hinaus kennt ein erfahrener Entwickler den richtigen Compiler für die jeweilige Plattform und verwendet beim Kompilieren der Anwendung die entsprechenden Flags. Auf Linux- oder Open Source-Plattformen ist dies kein Problem, da Sie Ihre Quelle verteilen und Installationsskripte erstellen können, die den Code mithilfe der entsprechenden Optimierung kompilieren. Auf Windows- oder Closed Source-Plattformen müssen Sie mehrere ausführbare Dateien mit jeweils spezifischen Optimierungen verteilen. Die Windows-Binärdateien, die bereitgestellt werden, basieren auf der vom MSI-Installationsprogramm erkannten CPU (mithilfe benutzerdefinierter Aktionen).


22
1. Microsoft hat diese Behauptungen nie aufgestellt, dass C # schneller ist. Ihre Behauptungen sind etwa 90% der Geschwindigkeit, schneller zu entwickeln (und damit mehr Zeit zum Optimieren) und aufgrund der Speicher- und Typensicherheit fehlerfreier. All dies ist wahr (ich habe 20 Jahre in C ++ und 10 Jahre in C #). 2. Die Startleistung ist in den meisten Fällen bedeutungslos. 3. Es gibt auch schnellere C # -Compiler wie LLVM (Intel herauszubringen bedeutet also nicht Apples to Apples)
ben

13
Die Startleistung ist nicht bedeutungslos. Dies ist in den meisten webbasierten Unternehmensanwendungen sehr wichtig. Aus diesem Grund hat Microsoft Webseiten eingeführt, die in .NET 4.0 vorinstalliert werden sollen (Autostart). Wenn der Anwendungspool von Zeit zu Zeit wiederverwendet wird, führt das erste Laden jeder Seite zu einer erheblichen Verzögerung für komplexe Seiten und zu Zeitüberschreitungen im Browser.
Richard

8
Microsoft machte die Behauptung geltend, dass die Leistung von .NET in früheren Marketingmaterialien schneller sei. Sie machten auch verschiedene Behauptungen über den Müllsammler geltend, die die Leistung kaum oder gar nicht beeinträchtigten. Einige dieser Behauptungen haben es in ihren früheren Ausgaben in verschiedene Bücher (über ASP.NET und .NET) geschafft. Obwohl Microsoft nicht ausdrücklich angibt, dass Ihre C # -Anwendung schneller als Ihre C ++ - Anwendung sein wird, werden möglicherweise allgemeine Kommentare und Marketing-Slogans wie "Just-In-Time bedeutet Run-It-Fast" ( msdn.microsoft.com/) veröffentlicht. en-us / library / ms973894.aspx ).
Richard

71
-1, dieser Rant ist voll von falschen und irreführenden Aussagen wie dem offensichtlichen Whopper "C # -Code wird NIEMALS schneller sein als eine C ++ - Anwendung"
BCoates

32
-1. Sie sollten Rico Mariani gegen Raymond Chens C # gegen C-Leistungskampf lesen : blogs.msdn.com/b/ricom/archive/2005/05/16/418051.aspx . Kurz gesagt: Einer der klügsten Mitarbeiter von Microsoft musste viel optimieren, um die C-Version schneller als eine einfache C # -Version zu machen.
Rolf Bjarne Kvinge

10

Meine erste Vermutung ist eine Compiler-Optimierung, da Sie nie root verwenden. Sie weisen es einfach zu und überschreiben es dann immer wieder.

Edit: verdammt, um 9 Sekunden schlagen!


2
Ich sage du bist richtig. Die eigentliche Variable wird überschrieben und darüber hinaus nie verwendet. Das csc würde höchstwahrscheinlich nur auf die gesamte Schleife verzichten, während der c ++ - Compiler sie wahrscheinlich belassen hat. Ein genauerer Test wäre, die Ergebnisse zu akkumulieren und dieses Ergebnis am Ende auszudrucken. Außerdem sollte man den Startwert nicht hart codieren, sondern ihn benutzerdefiniert lassen. Dies würde dem c # -Compiler keinen Raum geben, um Dinge wegzulassen.

7

Versuchen Sie, Ihren Code in zu ändern, um festzustellen, ob die Schleife entfernt wird

root += Math.Sqrt(i);

ähnlich im C-Code, und drucken Sie dann den Wert von root außerhalb der Schleife.


6

Möglicherweise bemerkt der c # -Compiler, dass Sie root nirgendwo verwenden, und überspringt einfach die gesamte for-Schleife. :) :)

Das mag nicht der Fall sein, aber ich vermute, was auch immer die Ursache ist, es hängt von der Implementierung des Compilers ab. Versuchen Sie, Ihr C-Programm mit dem Microsoft-Compiler (cl.exe, verfügbar als Teil des win32 sdk) mit Optimierungen und Freigabemodus zu kompilieren. Ich wette, Sie werden eine Perf-Verbesserung gegenüber dem anderen Compiler sehen.

EDIT: Ich glaube nicht, dass der Compiler die for-Schleife einfach optimieren kann, da er wissen müsste, dass Math.Sqrt () keine Nebenwirkungen hat.


2
Vielleicht weiß es das.

2
@Neil, @jeff: Einverstanden, das könnte man ziemlich leicht wissen. Abhängig von der Implementierung ist die statische Analyse von Math.Sqrt () möglicherweise nicht so schwierig, obwohl ich nicht sicher bin, welche Optimierungen speziell durchgeführt werden.
John Feminella

5

Was auch immer der Zeitunterschied ist. kann sein, dass "verstrichene Zeit" ungültig ist. Es wäre nur dann gültig, wenn Sie garantieren können, dass beide Programme unter genau den gleichen Bedingungen ausgeführt werden.

Vielleicht sollten Sie einen Sieg versuchen. entspricht $ / usr / bin / time my_cprog; / usr / bin / time my_csprog


1
Warum wird das abgelehnt? Geht jemand davon aus, dass Interrupts und Kontextwechsel die Leistung nicht beeinträchtigen? Kann jemand Annahmen über TLB-Fehler, Seitentausch usw. treffen?
Tom

5

Ich habe (basierend auf Ihrem Code) zwei weitere vergleichbare Tests in C und C # zusammengestellt. Diese beiden schreiben ein kleineres Array mit dem Modul-Operator für die Indizierung (es erhöht den Overhead, aber hey, wir versuchen, die Leistung [auf einer groben Ebene] zu vergleichen).

C-Code:

#include <stdlib.h>
#include <stdio.h>
#include <time.h>
#include <math.h>

void main()
{
    int count = (int)1e8;
    int subcount = 1000;
    double* roots = (double*)malloc(sizeof(double) * subcount);
    clock_t start = clock();
    for (int i = 0 ; i < count; i++)
    {
        roots[i % subcount] = sqrt((double)i);
    }
    clock_t end = clock();
    double length = ((double)end - start) / CLOCKS_PER_SEC;
    printf("Time elapsed: %f\n", length);
}

In C #:

using System;

namespace CsPerfTest
{
    class Program
    {
        static void Main(string[] args)
        {
            int count = (int)1e8;
            int subcount = 1000;
            double[] roots = new double[subcount];
            DateTime startTime = DateTime.Now;
            for (int i = 0; i < count; i++)
            {
                roots[i % subcount] = Math.Sqrt(i);
            }
            TimeSpan runTime = DateTime.Now - startTime;
            Console.WriteLine("Time elapsed: " + Convert.ToString(runTime.TotalMilliseconds / 1000));
        }
    }
}

Diese Tests schreiben Daten in ein Array (daher sollte es der .NET-Laufzeit nicht gestattet sein, die sqrt-Operation auszusortieren), obwohl das Array erheblich kleiner ist (kein übermäßiger Speicher verwendet werden wollte). Ich habe diese in der Release-Konfiguration kompiliert und in einem Konsolenfenster ausgeführt (anstatt über VS zu starten).

Auf meinem Computer variiert das C # -Programm zwischen 6,2 und 6,9 Sekunden, während die C-Version zwischen 6,9 und 7,1 variiert.


5

Wenn Sie den Code auf Assembly-Ebene nur in einem Schritt ausführen, einschließlich des Durchlaufens der Quadratwurzel-Routine, erhalten Sie wahrscheinlich die Antwort auf Ihre Frage.

Keine Notwendigkeit für fundiertes Raten.


Ich würde gerne wissen, wie das geht
Josh Stodola

Hängt von Ihrer IDE oder Ihrem Debugger ab. Pause am Anfang des pgm. Zeigen Sie das Demontagefenster an und starten Sie den Einzelschritt. Bei Verwendung von GDB gibt es Befehle zum schrittweisen Ausführen eines Befehls.
Mike Dunlavey

Das ist ein guter Tipp, der hilft, viel besser zu verstehen, was dort unten tatsächlich vor sich geht. Zeigt das auch JIT-Optimierungen wie Inlining und Tail Calls?
Gjvdkamp

Zu Ihrer Information: Für mich zeigte dies VC ++ mit fadd und fsqrt, während C # cvtsi2sd und sqrtsd verwendete, die meines Wissens SSE2-Anweisungen sind und daher erheblich schneller waren, wenn sie unterstützt wurden.
Danio

2

Der andere Faktor, der hier ein Problem sein kann, ist, dass der C-Compiler zu generischem nativem Code für die Prozessorfamilie kompiliert, auf die Sie abzielen, während die MSIL, die beim Kompilieren des C # -Codes generiert wurde, dann JIT kompiliert wird, um auf den genauen Prozessor abzuzielen, den Sie mit einem beliebigen Prozessor abgeschlossen haben Optimierungen, die möglich sein könnten. Daher kann der aus dem C # generierte native Code erheblich schneller sein als der C.


Theoretisch ja. In der Praxis macht das praktisch nie einen messbaren Unterschied. Ein oder zwei Prozent vielleicht, wenn Sie Glück haben.
Jalf

oder - wenn Sie einen bestimmten Codetyp haben, der Erweiterungen verwendet, die nicht in der zulässigen Liste für den 'generischen' Prozessor enthalten sind. Dinge wie SSE-Aromen. Versuchen Sie es mit einem höheren Prozessorziel, um festzustellen, welche Unterschiede Sie erhalten.
Gbjbaanb

1

Es scheint mir, dass dies nichts mit den Sprachen selbst zu tun hat, sondern vielmehr mit den verschiedenen Implementierungen der Quadratwurzelfunktion.


Ich bezweifle sehr, dass unterschiedliche SQLRT-Implementierungen so viele Unterschiede verursachen würden.
Alex Fort

Zumal selbst in C # die meisten mathematischen Funktionen immer noch als leistungskritisch gelten und als solche implementiert werden.
Matthew Olenik

fsqrt ist eine IA-32-Prozessoranweisung, daher ist die Sprachimplementierung heutzutage irrelevant.
Nicht sicher

Betreten Sie die sqrt-Funktion von MSVC mit einem Debugger. Es geht um viel mehr als nur um die Ausführung der Anweisung fsqrt.
bk1e

1

Eigentlich Jungs, die Schleife wird NICHT weg optimiert. Ich habe Johns Code kompiliert und die resultierende .exe untersucht. Die Eingeweide der Schleife sind wie folgt:

 IL_0005:  stloc.0
 IL_0006:  ldc.i4.0
 IL_0007:  stloc.1
 IL_0008:  br.s       IL_0016
 IL_000a:  ldloc.1
 IL_000b:  conv.r8
 IL_000c:  call       float64 [mscorlib]System.Math::Sqrt(float64)
 IL_0011:  pop
 IL_0012:  ldloc.1
 IL_0013:  ldc.i4.1
 IL_0014:  add
 IL_0015:  stloc.1
 IL_0016:  ldloc.1
 IL_0017:  ldc.i4     0x5f5e100
 IL_001c:  ble.s      IL_000a

Es sei denn, die Laufzeit ist intelligent genug, um zu erkennen, dass die Schleife nichts tut und sie überspringt?

Bearbeiten: Ändern des C # in:

 static void Main(string[] args)
 {
      DateTime startTime = DateTime.Now;
      double root = 0.0;
      for (int i = 0; i <= 100000000; i++)
      {
           root += Math.Sqrt(i);
      }
      System.Console.WriteLine(root);
      TimeSpan runTime = DateTime.Now - startTime;
      Console.WriteLine("Time elapsed: " +
          Convert.ToString(runTime.TotalMilliseconds / 1000));
 }

Die Ergebnisse in der verstrichenen Zeit (auf meinem Computer) liegen zwischen 0,047 und 2,17. Aber ist das nur der Aufwand für das Hinzufügen von 100 Millionen Additionsbetreibern?


3
Ein Blick auf die IL sagt nicht viel über Optimierungen aus, denn obwohl der C # -Compiler einige Dinge wie ständiges Falten und Entfernen von totem Code ausführt, übernimmt die IL dann und erledigt den Rest beim Laden.
Daniel Earwicker

Ich dachte, das könnte der Fall sein. Selbst wenn es zur Arbeit gezwungen wird, ist es immer noch 9 Sekunden schneller als die C-Version. (Ich hätte das überhaupt nicht erwartet)
Dana
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.