C++ If und Case performance

Zeboo

Lt. Commander
Registriert
Juli 2008
Beiträge
1.562
Hallo.

Also was man schon (hoffe ich mal) klar sagen kann:
Wenn man zwischen zwei Befehlen unterscheiden möchte, reicht eine einfache if.

Wenn man eine riesige Liste von Befehlen hat ist Case sinnvoll. Nicht nur weil das schön ist, sondern auch weil das schneller geht.

Jetzt wollte ich mal Fragen ob es da schon irgendwo fertige Programme oder Benchseiten gibt die zeigen wie viel mal ein Case (auf dem gleichen PC) schneller sein kann wie If (und/oder umgekehrt).

Eigentlich wollte ich das nicht nur für C++ wissen, sondern auch für C und Java. Falls jemand paar tolle Links oder sonstwas hätte würde ich mich freuen.

Danke und Gruß
 
Ich würde mal behaupten, dass die If-Anweisung sogar schneller ist.
Steinigt mich wenn ich falsch liege :>
 
switch/case kann grob um den faktor schneller sein, wieviele case-anweisungen es gibt. d.h. gibt es 5 case-anweisungen, dann kann es um den faktor 5 schneller sein als das ganze per if zu machen, im schnitt um faktor 2.5 (die hälfte)

der grund ist einfach. bei if wird quasi mit jedem der werte verglichen, bis der richtige gefunden wird. bei case wird dem wert direkt eine sprungaddresse zugeordnet was quasi in konstanter zeit geht (ist nicht ganz richtig).

warum meine letzte aussage nicht ganz richtig ist, aber ind er praxis man sich das so denken kann liegt daran, dass tatsächlich die zuordnung wert->sprungaddresse immer noch über vergleiche stattfindent, allerdings weit effizientere aber für den programmierer versteckt.
 
Also ich glaube mich zu erinnern, dass es in sachen performance von if und case bei einer höheren programmiersprache keinen unterschied gibt.
Im endeffekt führt der rechner doch die gleichen befehle aus (wenn das, dann mach das), wenn das richtig kompiliert wird, müsste sogar der gleiche assemblercode rauskommen.

Just my 2c,
Uschi ;)
 
Dann gibt es Case nur aus spaß? ;)

@dammi: Ausserdem wenn ich einen

PHP:
if(x == 'bla")
-
else if (x == 'muh')
-
else if (x == 'muh2')
-
else if (x == 'muh3')
-
else if (x == 'muh4')
-
else if (x == 'muh5')
-
else if (x == 'muh6')
-
else if (x == 'muh7')
-
else if (x == 'muh8')
-
else if (x == 'muh9')
...

habe. Und x == muh9, dann wird man nach so einem code die cpu bestimmt länger brauchen wie wenn man das mit Case gemacht hätte.
 
ach ncohwas: die effektivität von switch/case hängt aber stark von den werten der case anweisungen ab. wahllose werte kann der compiler nicht immer zu einem schnellausführbaren code übersetzten.
 
so wie ich das sehe kommt bei einer if kaskade der selbe assemblercoder raus wie bei case
case lässt sich nur sehr viel angenehmer lesen / schreiben und ist verständlicher
 
Jo, ist historisch gewachsen und so geblieben. Mir wurde beigebracht, dass es heute keinen gravierenden Performanceunterschied mehr macht :>
 
@Zeboo:
nein, dein beispiel ist denkbar ungünstig. wenn der compiler nicht richtig gut zaubern kann, dann hast du gerade ein super beispiel gefunden, indem case und if gleich gut ist.

strings als case-werte sind so ziemlcih das schlechteste, was man dafür nehmen kann.

um das mal genauer anzugehen:
if und case ergeben nicht immer den glecihen code. das hängt von den werten der case anweisungen ab.

z.b. sind die werte eng bei einander, z.b. 5,6,7,8,9, dann kann das der compiler sehr gut optimieren und in konstanter zeit zur richtigen case-anweisung springen. einfach vom verlgeichswert die 5 abziehen um in der tabelle der sprungadressen die richtige zeile zu finden.

deswegen muss man die werte die in dem switch/case benutzt werden vorher durch den programmier optimieren, damit auch jeder compiler das dann optimal umsetzten kann.

edit: an die anderen: nein, ihr leigt falsch. ihr macht diese erfahrung nur deshalb, weil die wenigsten die switch/case anweisung richtig verwenden und zuvor die werte richtig anpassen! deswegen kommt dann das gleiche raus, wie bei einer if-anweisung. macht das mal richtig, dann wird ein guter compiler was ganz anderes produzieren. (siehe mein beispiel oben).
 
Zeboo schrieb:
Dann gibt es Case nur aus spaß? ;)

@dammi: Ausserdem wenn ich einen

PHP:
if(x == 'bla")
-
else if (x == 'muh')
-
else if (x == 'muh2')
-
else if (x == 'muh3')
-
else if (x == 'muh4')
-
else if (x == 'muh5')
-
else if (x == 'muh6')
-
else if (x == 'muh7')
-
else if (x == 'muh8')
-
else if (x == 'muh9')
...

habe. Und x == muh9, dann wird man nach so einem code die cpu bestimmt länger brauchen wie wenn man das mit Case gemacht hätte.

Select case x
case muh1​
case muh2​
case muh3​
.
.
.
case muh9​

dauert doch genauso lange?!
 
mich würde das auch mal interessieren, ich würde nämlich sagen dass sie letztendlich fast die gleiche Zeit brauchen, da es z.b. bei Java oder so vom Compiler auf das gleiche abgebildet wird... selbst wenn eins von beiden viel schneller ist, würde ich das benutzen was an den entsprechenden Stellen besser lesbar ist ;) die Unterschiede sollten bei der Laufzeit eines Programms nicht auffallen KÖNNEN! ^^

OT:
lustig wenn man google nach "performance if case" fragt, ist dieser Thread schon ganz oben :D
 
@dammi & appleyard: Seh ich auch so.
 
@Uschi: nein weil wir doch eben gesagt haben, dass bei if alle anweisungen einzeln durchgeprüft werden und bei case nich alle durchgerechnet werden sondern dank tabelle direkt zum Ziel springen kann. Aber genau wegen solche Aussagen wäre es cool wenn mal jemand eine Benchseite oder sowas finden könnte..
 
ich habs eigentlich schon oben ausführlich erklärt:
der zugriff über die tabelle der sprungadressen ist NUR dann schneller, wenn man schnell die entsprechende adresse finden kann. der compiler ist kein genie der da zaubern kann. aber wenn man klug die werte wählt (z.b. durch eine einfach umrechnung, die nicht zuviel zeit kosten darf), dann kann der compiler das schnell erledigen.

edit: wie schon gesagt: die wenigsten wissen das und machend as richtig. deswegen glauben mittlerweile soviele sitch/case kommt aufs gelcihe wie if/else. das sit quatsch und leigt nur an der falschen verwendung der programmierer.
 
Naja es hängt von den Rahmenbedingungen ab:
- Welche Programmiersprache, welcher Compiler (-> wie gut optimiert der)?
- Was wird verglichen? Für Strings sollte man von Switch Abstand nehmen - wenn die Sprache sowas überhaupt zulässt

Generelle Aussagen kann man nie machen. Man muss sich auch fragen: Spielt es aus Leistungssicht überhaupt eine Rolle? Eine Optimierung eines solchen Anweisungsblocks lohnt sich nur, wenn:
- z.B. Echtzeitbedingungen erfüllt werden müssen und es mitunter auf jeden Takt ankommt
- der Block sehr häufig durchlaufen werden muss

Wenn man um IFs nicht umher kommt, sollte man die Bedingungen nach Möglichkeit der Wahrscheinlichkeit nach sortieren.

Außerdem sind manche Ausdrücke halt eleganter und übersichtlicher mit IFs, andere mit Switches. Bei IF-Anweisungen sind auch ganz andere "Bedingungen" möglich...
 
Zuletzt bearbeitet: (was für ein geiler Schreibfehler :-))
1668mib schrieb:
Spielt es aus Leistungssicher überhaupt eine Rolle? Eine Optimierung eines solchen Anweisungsblocks lohnt sich nur, wenn:
- z.B. Echtzeitbedingungen erfüllt werden müssen und es mitunter auf jeden Takt ankommt
- der Block sehr häufig durchlaufen werden muss
richtig, eigentlich ist es doch fast immer unwichtig, auch in Blöcken die oft durchlaufen werden, wir sprechen hier von Nanosekunden Zeitunterschied.
Und wer so strenge Echtzeitbedingungen hat, dass der Unterschied If oder Case relevant ist, wird dies vermutlich in Assembler umsetzen und die Aufgabe nicht einem Compiler überlassen, der sonstetwas fabrizieren kann.

Performance-Charateristika werden durch Datenstrukturen und Algorithmen beeinflusst, und kaum durch ein If oder Case, ein If oder Case sind Mikrooptimierungen, und die sollte man nur machen, wenn man wirklich genau weiß, dass sie einen großen Einfluss haben werden bzw. dass diese das Problem sind (also ehrlich gesagt so gut wie nie)
 
Zuletzt bearbeitet:
um mal deine bezeichnung aufzugreifen: mikrooptimerungen sind natürlcih nur dann sinnvoll, wenn sie teile betreffen, die oft durchlaufen werden. andererseits schaden scih acuh nicht.

es spricht oft nichts gegen switch/case gegenüber if-anweisungen, wenn man die situation von vielen aufeinanderfoglenden if-else-anweisungen hat (nur da bringt case überhaupt was).

allerdings ist es falsch anzunehmen, dass sowas kaum vorkommt bzw. das man dann auf assembler wechseln tut. das kommt stark auf das anwendungsgebiet an. und dank guter c/c++-compiler ist es somit in den meisten fällen nicht mehr nötig auf assaembler zurückzugreifen.

genau deswegen gibt es verdammt gute c-implementierungen diverser krypto-algorithmen und anderer. assembler ist da größtenteils überflüssig geworden, bzw. bringt kaum noch was im vergleich.

das optmierungen einzelner anweisungen nur dann nennenswert einen effekt haben, wenn sie in einem starkwiederholeden block auftretten ist trivial. aber sie zu vernachlässigen ist schelcht. und im falle von if-esle vs switch-case kann man bei geschicktem einsatz für eine mikrooptimierung einen hohen gewinn erzielen.

edit: und fall man davon wenig ahnung hat, dann ist man mit einer switch-case anweisung wenigsten nie schlechter drann, mit glück aber besser.
 
Dese schrieb:
um mal deine bezeichnung aufzugreifen: mikrooptimerungen sind natürlcih nur dann sinnvoll, wenn sie teile betreffen, die oft durchlaufen werden. andererseits schaden scih acuh nicht.
if und case sind ja nur ein Beispiel für Mikrooptimierungen, es gibt ja noch viele weitere, und oftmals entsteht aus diesen deutlich schlechter lesbarer Code, deshalb sollten Mikrooptimierungen nur mit bedacht gemacht werden.

Dese schrieb:
es spricht oft nichts gegen switch/case gegenüber if-anweisungen, wenn man die situation von vielen aufeinanderfoglenden if-else-anweisungen hat (nur da bringt case überhaupt was).
klar, if/switch ist kein Problem, aber wer so anfängt wird noch ganz viele weitere Entscheidungen für Mikrooptimierungen treffen:
Hmm, ein Methodenaufruf mit dem Stack ist doch eigentlich viel zu viel Performanceverlust, ich sollte den Code lieber inlinen.

Dese schrieb:
das optmierungen einzelner anweisungen nur dann nennenswert einen effekt haben, wenn sie in einem starkwiederholeden block auftretten ist trivial. aber sie zu vernachlässigen ist schelcht. und im falle von if-esle vs switch-case kann man bei geschicktem einsatz für eine mikrooptimierung einen hohen gewinn erzielen.
selbst bei tausendmaligen Durchlaufen eines Blockes wird der Unterschied if/else kaum einen Unterschied bringen, garantiert wird an einer anderen Stelle milliardenfach mehr Leistung gefressen ;) Ein Algorithmus oder eine Datenstruktur die nicht optimal ist zu optimieren und tausendmal sinnvoller.
Ich glaube keiner hier wird beim Profiling seiner Anwendungen festgestellt haben, dass er immense Performancegewinne beim Tausch eines ifs durch eine case bekommen hat.
Solche Optimierungen machen heute fast nur noch Sinn in integrierten Schaltungen bzw. Mikroprozessoren, aber dort muss man auch ganz andere Probleme bewältigen (wenige KB Speicher)

Dese schrieb:
edit: und fall man davon wenig ahnung hat, dann ist man mit einer switch-case anweisung wenigsten nie schlechter drann, mit glück aber besser.
jup erstmal immer auf Lesbarkeit setzen, Optimierungen kommen ganz am Schluss.
 
wir waren hier aber im thread beim thema if-else vs switch-case und cnith bei anderen optimierungen.

das andere optimierungen wichtiger sind ist ebenfalls nicht thema hier. das ist ja alels richtig, aber von keinem hier bestritten. dief rage war wie switch-case imv erglecih zu if-else abschneidet und richtig benutzt bei gutem compiler kann das nen grossen faktor ausmachen.

dass das im verlgeih zu anderen dingen, die bremsen immer noch äusserst wenig ist, ist ein anderes thema und von dem konkreten problem/programm abhängig.

p.s. tausendfaches durchlaufen ist wenig, da hät ich jetzt nicht die worte "selbst bei" verwendet. in relevanten anwedungen reden wir eher von millionenfachen wiederholungen. hinzukommt, dass man die plattform mitberücksichtigen muss. z.b. macht auf embedded-systemen solche optimerugngen einfacher anweisungen einen viel größeren sinn, da die laufzeit dieser einen größeren anteil an der gesamtlaufzeit haben.

es summiert ich alles auf. bei einem tausch macht's noch nciht viel aus. aber optmiert man mehr fängt es langsam an sich unter umständen zu rentieren... in manchen fällen. deswegen ist es gut, wenn man als programmierer darüber bescheid weiß, damit man weiß, wann man es einsetzten sollte.
 
ich habs mal mit dem Visual Studio unter VB.Net 4.0 probiert:

50.000.000 Durchläufe, 20 Entscheidungszweige mit Stringvergleich und Stringzuweisung in jedem Zweig.

Ergebnis:

if-else-Konstrukt: 21.579,2341 ms
Select-Case: 21.238,2147 ms

Der entstandene Unterschied kann durchaus von anderen Prozessen oder vom Threadmanager von Windows kommen. Daher würd ich erstmal sagen: Bei den .Net-Compilern ist es zeitlich irrelevant.

Vielleicht hat noch jemand n Ansi C-Compiler da, vll sogar unter Linux o.ä.? das würde mich auch interessieren.
 
Zurück
Oben