for vs. foreach



  • Hi,

    ich habe mal ne reine Performance-Frage zum Thema Arrays und Listen bezügliche Schleifen.

    Nehmen wir mal an ich habe ein Array/List<T> vom Typ string mit mehreren Namen drin:

    string[] names = fillWithNames ();
    

    Diese Liste möchte ich nun durchlaufen und jeden Namen an eine weitere Funktion geben, das mach ich bisher mit foreach:

    foreach (string name in names)
        parseName (name);
    

    Dabei geht es auch mit der guten alten for-Schleife:

    for (int i = 0; i < names.Length; ++i)
        parseName (names[i]);
    

    Nun was ist besser für die Performance?

    Von der Optik her finde ich Variante 1 besser, aber geht mir auch um Performance - daher frag ich mal die Experten 🙂

    Apropos noch ne Frage am Rande: wie kann ich aus nem Array/List doppelte Elemente entferne (möglichst Performant)

    Danke im voraus!



  • Mess es einfach aus. Oder noch besser: schau dir an, in was der Compiler es uebersetzt. Es wuerd mich aber extrem wahnsinnig wundern, wenns da einen messbaren Unterschied gaeb...



  • Im Falle von Collections die nicht auf Arrays basieren (z.B. verkettete Listen) ist die Variante mit for immer langsamer.



  • und in der for-schleife das i < name.lenght ist auch nicht so gut, da in jedem durchlauf die abfrage stattfindet, und diese zeit braucht, lieber vorher die känge in einer variablen speichern!



  • Das Gegenteil ist meistens der Fall. Wenn du die Länge in einer Variable speicherst, dann muss der Compiler schlau genug sein (was er bislang anscheinend nicht ist) zu erkennen, dass der Wert der Variable der Länge des Arrays entspricht und er so die Indexüberprüfung fallen lassen kann. Das ist offensichtlicher, wenn er array.Length sieht. Wenn du Pech hast, handelst du dir durch die vermeintliche Optimierung eine unnötige Indexüberprüfung pro Durchlauf ein.



  • sorry, aber das kann ich so nicht bestätigen, da ich diese tests schon gemacht habe!

    Ich habe mehrere schleifen getestet, und immer war die nichtoptimierte langsamer!
    Klar kann unter umständen vielleicht dein problem auftreten, aber ich hatte es bisher noch nicht! (btw wurde mir die optimierung auch in einigen fachbüchern empfohlen)



  • In diesem von forler beschriebenen Fall, gibt es kaum Unterschiede in der Performanz. So schlau ist der Compiler allemal wenn's um Arrays geht.

    Ich habe mir das IL-Code dennoch angesehen. Wie erwartet: Nach der Initialisierung der Variablen wird eine Schleife ausgeführt die in beiden Fällen quasi-identisch ist.

    Eine Messung ergab bei einem Array mit 100.000 strings Unterschiede im Zehntel-Millisekundenbereich.



  • ser1al_ausgeloggt schrieb:

    sorry, aber das kann ich so nicht bestätigen, da ich diese tests schon gemacht habe!

    Dann hast Du beim Testen einfach Fehler gemacht. Die „nicht-optimierte“ Variante ist *definitiv* schneller, weil der Compiler hier erkennt, was man vorhat und den Aufruf abwandelt, sodass erstens der Vergleich auf x.Length flachfällt (der wird aber sowieso geinlined, fällt also nicht ins Gewicht) und außerdem entfernt der Compiler (nur hier!) die Array-Range-Checks, weil er sicher ist, dass nie ein ungültiger Index verwendet werden kann.

    Das behauptet zumindest Anders Hejlsberg, der Chefentwickler des C#-Compilers. Es gibt dazu aber auch Analysen im Netz, die das empirisch bestätigen.

    (btw wurde mir die optimierung auch in einigen fachbüchern empfohlen)

    Leider sind viele Fachbücher einfach schlecht oder nicht aktuell.

    Und zusätzlich, um es nochmal zu betonen: Properties können vom JITTer trivial geinlined werden (und werden dies auch). Den Wert von 'x.Length' zwischenzuspeichern ist also wirklich überflüssig.


Anmelden zum Antworten