Es ist wichtig, die Anweisung C # switch nicht mit der Anweisung CIL switch zu verwechseln.
Der CIL-Schalter ist eine Sprungtabelle, für die ein Index für eine Reihe von Sprungadressen erforderlich ist.
Dies ist nur nützlich, wenn die Fälle des C # -Schalters benachbart sind:
case 3: blah; break;
case 4: blah; break;
case 5: blah; break;
Aber von geringem Nutzen, wenn sie nicht:
case 10: blah; break;
case 200: blah; break;
case 3000: blah; break;
(Sie benötigen eine Tabelle mit einer Größe von ca. 3000 Einträgen und nur 3 verwendeten Steckplätzen.)
Bei nicht benachbarten Ausdrücken kann der Compiler beginnen, lineare If-else-if-else-Prüfungen durchzuführen.
Bei größeren nicht benachbarten Ausdruckssätzen kann der Compiler mit einer binären Baumsuche und schließlich mit den letzten Elementen beginnen, wenn-sonst-wenn-sonst.
Bei Ausdruckssätzen, die Klumpen benachbarter Elemente enthalten, kann der Compiler eine binäre Baumsuche und schließlich einen CIL-Schalter durchführen.
Dies ist voll von "Mai" und "Macht" und hängt vom Compiler ab (kann bei Mono oder Rotor abweichen).
Ich habe Ihre Ergebnisse auf meinem Computer anhand benachbarter Fälle repliziert:
Gesamtzeit für die Ausführung eines 10-Wege-Schalters, 10000 Iterationen (ms): 25.1383
ungefähre Zeit pro 10-Wege-Schalter (ms): 0,00251383
Gesamtzeit für die Ausführung eines 50-Wege-Schalters, 10000 Iterationen (ms): 26.593
ungefähre Zeit pro 50-Wege-Schalter (ms): 0,0026593
Gesamtzeit für die Ausführung eines 5000-Wege-Schalters, 10000 Iterationen (ms): 23.7094
ungefähre Zeit pro 5000-Wege-Schalter (ms): 0.00237094
Gesamtzeit für die Ausführung eines 50000-Wege-Schalters, 10000 Iterationen (ms): 20.0933
ungefähre Zeit pro 50000-Wege-Schalter (ms): 0.00200933
Dann habe ich auch nicht benachbarte Fallausdrücke verwendet:
Gesamtzeit für die Ausführung eines 10-Wege-Schalters, 10000 Iterationen (ms): 19.6189
ungefähre Zeit pro 10-Wege-Schalter (ms): 0.00196189
Gesamtzeit für die Ausführung eines 500-Wege-Schalters, 10000 Iterationen (ms): 19.1664
ungefähre Zeit pro 500-Wege-Schalter (ms): 0.00191664
Gesamtzeit für die Ausführung eines 5000-Wege-Schalters, 10000 Iterationen (ms): 19,5871
ungefähre Zeit pro 5000-Wege-Schalter (ms): 0,00195871
Eine nicht benachbarte 50.000-Fall-Switch-Anweisung würde nicht kompiliert.
"Ein Ausdruck ist zu lang oder zu komplex, um in der Nähe von 'ConsoleApplication1.Program.Main (string [])' kompiliert zu werden.
Was hier lustig ist, ist, dass die binäre Baumsuche etwas (wahrscheinlich nicht statistisch) schneller erscheint als die CIL-Schalteranweisung.
Brian, Sie haben das Wort " Konstante " verwendet, das aus Sicht der rechnergestützten Komplexitätstheorie eine ganz bestimmte Bedeutung hat. Während das vereinfachte benachbarte Ganzzahlbeispiel CIL erzeugen kann, das als O (1) (konstant) betrachtet wird, ist ein spärliches Beispiel O (log n) (logarithmisch), gruppierte Beispiele liegen irgendwo dazwischen und kleine Beispiele sind O (n) (linear) ).
Dies betrifft nicht einmal die String-Situation, in der eine statische Generic.Dictionary<string,int32>
Aufladung erstellt werden kann, und führt bei der ersten Verwendung zu einem deutlichen Overhead. Die Leistung hier hängt von der Leistung von ab Generic.Dictionary
.
Wenn Sie die C # -Sprachenspezifikation (nicht die CIL-Spezifikation) überprüfen, finden Sie "15.7.2 Die switch-Anweisung" erwähnt "konstante Zeit" nicht oder dass die zugrunde liegende Implementierung sogar die CIL-switch-Anweisung verwendet (seien Sie sehr vorsichtig bei der Annahme solche Sachen).
Letztendlich ist ein C # -Schalter gegen einen ganzzahligen Ausdruck in einem modernen System eine Operation im Submikrosekundenbereich und normalerweise keine Sorge wert.
Natürlich hängen diese Zeiten von den Maschinen und Bedingungen ab. Ich würde diesen Timing-Tests keine Aufmerksamkeit schenken, die Mikrosekunden-Dauer, von der wir sprechen, wird durch die Ausführung von "echtem" Code in den Schatten gestellt (und Sie müssen "echten Code" einfügen, sonst optimiert der Compiler die Verzweigung) oder Jitter im System. Meine Antworten basieren auf der Verwendung von IL DASM , um die vom C # -Compiler erstellte CIL zu untersuchen. Dies ist natürlich nicht endgültig, da die tatsächlichen Anweisungen, die die CPU ausführt, dann von der JIT erstellt werden.
Ich habe die endgültigen CPU-Anweisungen überprüft, die tatsächlich auf meinem x86-Computer ausgeführt wurden, und kann einen einfachen benachbarten Set-Schalter bestätigen, der Folgendes ausführt:
jmp ds:300025F0[eax*4]
Wo eine binäre Baumsuche voll ist von:
cmp ebx, 79Eh
jg 3000352B
cmp ebx, 654h
jg 300032BB
…
cmp ebx, 0F82h
jz 30005EEE