Laden...

Performance(vergleich) der verschiedenen Schleifentypen (foreach, for, while)

Erstellt von sreischl vor 15 Jahren Letzter Beitrag vor 15 Jahren 6.894 Views
S
sreischl Themenstarter:in
59 Beiträge seit 2008
vor 15 Jahren
Performance(vergleich) der verschiedenen Schleifentypen (foreach, for, while)

Hallo leute...

Ich denke, dass es bestimmt schon einiges zu besprechen gab über dieses Thema... aber leider finde ich irgendwie nix...
Vielleicht bin ich zu dumm dafür die richtigen suchkriterien zu benutzen...

Trotzdem meine Frage:

Wie ist die Geschwindigkeitsverteilung bei Schleifen?

Ist For schneller als Foreach?
Ist For schneller als DoWhile?
etc...etc...

Würde mich über Antworten freuen

Viele Grüße
sreischl

T
109 Beiträge seit 2008
vor 15 Jahren

hi,

das einfachste is immer noch es selbst auszuprobieren!

mach dir 3 schleifen die gleich oft durchlaufen. nimm vorher das datum und nachher und mach dann mit timespan die differenz darauf! die kannste dir dann ausgeben lassen und bist dann viel schlauer!

(bitte teil uns das ergebnis mit)

Torley

3.971 Beiträge seit 2006
vor 15 Jahren

Soweit ich weiß, gibt es aus IL-Sicht nur eine While-Schleife. For und Foreach werden entsprechend mit einer While-Schleife abgebildet.

Es gibt 3 Arten von Menschen, die die bis 3 zählen können und die, die es nicht können...

6.862 Beiträge seit 2003
vor 15 Jahren

Hallo,

die Frage an sich macht nicht viel Sinn. Bei Schleifen ist der eigentliche Schleifencode der Teil der am allerwenigsten in die Laufzeit mit eingeht im Vergleich zum eigentlich Code der in der Schleife ausgeführt wird. Außerdem lässt sich relativ schlecht sagen was wirklich an Maschienenbefehlen rauskommt für die Schleife, je nachdem wie der Jitter optimiert. Auch sind deshalbs Tests mit leeren Schleifen wenig sinnvoll, da weitab der Realität. Ist genauso als wenn ich ne in ner Liste mit nen paar Elementen ne lineare Suche mach, sag die ist gut weil schneller als SuchmethodeXYZ, aber sobald ich sehr viele Elemente hab wird man sich das linear schnell sparen wollen.

Was man wohl sagen kann ist das bei foreach mit nem Enumerator gearbeitet wird, das zumindest eine Objektinstanzierung beinhaltet und es so einen geringen Mehraufwand gegenüber einer normalen Schleife gibt. Aber! In vielen Fällen steht im C# Code nen foreach, aber daraus wird auch ne ganz normale while Schleife gemacht, einfach weil der Typ über den iteriert wird, keinen Enumerator brauch. z.B. bei Arrays. Von daher kann man auch nicht prinzipiell sagen dass foreach langsamer ist als for.

Man sollte die Schleife nehmen die zum Problem am besten passt, die den lesbarsten Code darstellt und dann ist gut. Über die Schleifenperformance muss man sich wenig Sorgen machen, da gibts viel schlimmere Stolperfallen.

Baka wa shinanakya naoranai.

Mein XING Profil.

T
109 Beiträge seit 2008
vor 15 Jahren

So ich hab jetzt selbst mal einen test durchgeführt!

rauskam das for schneller ist als while! foreach hab ich nicht getestet weil mir grad keine anwendung einfallen ist die ich in allen 3 aus führen kann!


        private void btnFor_Click(object sender, EventArgs e)
        {
            DateTime dtstart = DateTime.Now;
            int läufe = int.Parse(txtLäufe.Text);
            int zähler = 0;
            for (int i = 0; i < läufe; i++)
            {
                zähler++;
            }
            DateTime dtende = DateTime.Now;
            TimeSpan tszeit = dtende - dtstart;
            txtFor.Text += "\r\n" + tszeit.Seconds.ToString() + "." + tszeit.Milliseconds.ToString();
        }

        private void btnWhile_Click(object sender, EventArgs e)
        {
            DateTime dtstart = DateTime.Now;
            int läufe = int.Parse(txtLäufe.Text);
            int zähler = 0;
            while (zähler < läufe)
            {
                zähler++;
            }
            DateTime dtende = DateTime.Now;
            TimeSpan tszeit = dtende - dtstart;
            txtWhile.Text += "\r\n" + tszeit.Seconds.ToString() +"." +tszeit.Milliseconds.ToString();
        }

Hier noch ein ergebnis:

While:
0.828
0.843
0.859
0.843
0.843
0.843

For:
0.796
0.796
0.796
0.796
0.796
0.781

Anzahl läufe:
200000000

Im Anhang ist das Projekt

Torley

946 Beiträge seit 2008
vor 15 Jahren

Sehr erstaunlich. Ich hätte gedacht, das es egal ist, welche Variante man verwendet

Ausgabe:
for while
6.743 7.730
6.755 7.743

Die Anzahl der Läufe war auch 200000000.

Im Release kamen aber folgende Ausgaben:

:::

~1.31 - ~1.38

Dort kann man sogar erkennen, dass die while-Schleife fast 5% schneller ist.

S
sreischl Themenstarter:in
59 Beiträge seit 2008
vor 15 Jahren

Ok.
Ich danke euch für eure Antworten...

Besonderer dank geht an talla:
Deine Aussagen haben sich bewärt...

Mein Fazit:
Die paar millisekunden die mir die eine Schleife bringt ist es im normalfall nicht wert, die Leserlichkeit zu beeinträchtigen.

Die eigentliche Code-Optimierung steckt überall, aber nicht an der Schleife die man macht.

Merci!

Viele Grüße aus der Oberpfalz!

G
43 Beiträge seit 2008
vor 15 Jahren

Torley: In der for-Schleife zaehlst du i und zaehler hoch, in der while-Schleife dagegen nur zaehler.
Ich habe mir mal ein einfaches Konstrukt beider Schleifen-Typen in der IL angeschaut und sie sind identisch.
Was anderes haette mich auch ehrlich gesagt verwundert.

1.200 Beiträge seit 2007
vor 15 Jahren

Ich denke auch, dass die Deltas andere Ursachen haben.

Shift to the left, shift to the right!
Pop up, push down, byte, byte, byte!

YARRRRRR!

S
8.746 Beiträge seit 2005
vor 15 Jahren

Beim Zugriff auf Collections innerhalb einer Schleife sollte man foreach oder for verwenden. Bei for-Schleifen aber unbedingt im Abbruch-Kriterium direkt col.Length verwenden. Nicht etwa sowas:

int len = col.Length;
for(int i = 0; i < len; i++)
{
...
}

Beliebt bei C-Codern, schlecht bei .NET. Denn in diesem Fall wird der Range-Check nicht abgeschaltet.

P
66 Beiträge seit 2006
vor 15 Jahren

Patric Smacchia (Entwickler von NDepend) hat sich schonmal mit der selben Fragestellung beschäftigt.

Den Artikel dazu findest du unter

http://codebetter.com/blogs/patricksmacchia/archive/2008/11/19/an-easy-and-efficient-way-to-improve-net-code-performances.aspx

T
109 Beiträge seit 2008
vor 15 Jahren

Beim Zugriff auf Collections innerhalb einer Schleife sollte man foreach oder for verwenden. Bei for-Schleifen aber unbedingt im Abbruch-Kriterium direkt col.Length verwenden.

fals du damit mich meinst: ich benutze immer direkt col.length doch war ich mir bei dem beispiel nicht sicher, ob die abfrage von col.length nicht länger dauert als eine abfrage eines ints. deshalb hab ich die länge erst in einen int gepackt!

ich bin mir 80% sicher das int.Parse(txtLäufe.Text); länger dauert als einen int zu nehmen

(soll jetzt nicht böse oder so sein einfach nur eine erklärung wieso ich es im beispiel mit der int vaiable gemacht habe)

Torley

3.971 Beiträge seit 2006
vor 15 Jahren

Hallo Torley,
bitte ließ dir das von Svenson nochmal durch und schau dir das Beispiel an. Das bezog sich auf Arrays/Listen, denn dort kann der C#Compiler/JIT entsprechend optimieren.

Es gibt 3 Arten von Menschen, die die bis 3 zählen können und die, die es nicht können...

U
1.688 Beiträge seit 2007
vor 15 Jahren

Beliebt bei C-Codern, schlecht bei .NET. Denn in diesem Fall wird der Range-Check nicht abgeschaltet.

Hmmm - könntest Du das bitte etwas näher ausführen? Bezieht sich das auf Änderungen des Arrays oder einer Liste in der Schleife?

Was die Geschwindigkeit der Schleifen angeht - wenn man sie tatsächlich testen will, ist es besser, sie in einer Consolen-Anwendung mit der Stopwatch-Klasse und im Release-Mode zu untersuchen.

Ein anderer Thread zum Thema findet sich hier:
foreach oder for? was ist schneller? Ist die Reihenfolge festgelegt?