Wie wirkt sich die Verwendung von vielen Iteratoren in C# auf die Speichernutzung aus? Nehmen wir ein Programm an, das Tausende von foreach
-Schleifen ausführt - weist jede Schleife ein temporäres Objekt auf dem Heap über einen Aufruf an GetEnumerator
zu? Führt die CLR irgendeine Art von Optimierung durch (z. B. Stapelzuordnung von IEnumerator
Objekten)? Oder ist das einfach nicht wichtig genug, um sich Sorgen zu machen?Speichernutzung von Iteratoren in C#
Antwort
Es ist einfach nicht signifikant genug, um sich in den meisten Fällen Sorgen zu machen. Wie Eric hervorhebt, gibt es möglicherweise einige Fälle, in denen es wichtig ist, aber sie sind ziemlich wenige und weit in meiner Erfahrung.
Wenn Sie Hunderttausende von foreach
Schleifen tun, vermutlich tun Sie tatsächlich Arbeit innerhalb dieser Schleifen. Das wird mit ziemlicher Sicherheit wichtiger sein als die Iteratoren selbst.
Beachten Sie, dass die Verwendung von foreach
über ein Array (das zur Kompilierungszeit als Array bekannt ist) sowieso nicht IEnumerable<T>
verwendet - es verwendet direkte Indizierung. Ich würde meinen Code auf dieser Grundlage jedoch nicht ändern.
Wie immer, wenn Sie über die Leistung besorgt sind, müssen Sie es messen und profilieren. Engpässe sind fast nie dort, wo Sie sie erwarten.
Oft kann der Compiler eine foreach-Schleife in eine einfache Schleife optimieren, die nur eine Indexvariable auf dem Stack (oder in einem Prozessorregister) benötigt.
Wenn immer noch ein Iterator verwendet wird, sind die meisten davon Strukturen, so dass sie nur auf dem Stapel statt auf dem Heap zugewiesen werden.
Die wenigen Iteratoren, die Klassen sind, sind immer noch recht klein und schnell. Sie könnten Millionen von ihnen ohne spürbare Auswirkungen erstellen.
Klingt gut ... Kurze Folgefrage: Wenn ich die IEnumerable-Schnittstelle implementiere, gibt die GetEnumerator-Methode definitionsgemäß einen IEnumerator zurück. Wenn mein benutzerdefinierter Iterator eine Struktur ist, gehe ich davon aus, dass er daher als ein Box-Objekt zurückgegeben wird? –
Jen, _carefully_ sehen, wie List
Aber noch einmal, wie Jon sagt, tun Sie nicht diese doof Sache, wenn Sie solide Daten haben, dass das Erstellen von Enumeratoren auf dem Heap eine Hauptursache für ein wirkliches, kundenbeeinträchtigendes Leistungsproblem ist. Veränderbare Werttypen verursachen alle Arten von seltsamen Problemen, die teuer zu debuggen und schwer zu verstehen sind. –
Obwohl dies, wie immer, ein exzellenter Rat Jon war, zeigten unsere Leistungstests in einigen realen Szenarien einen signifikanten Leistungseinfluss durch die Heapzuweisung/Speicherbereinigung von Iteratoren. Deshalb ist der Enumerator der Liste ein böser veränderbarer Werttyp und kein Referenztyp. Aber natürlich ist das Stichwort "unser Leistungstest" - wie Sie bemerken, ist es töricht, Leistungsentscheidungen ohne Daten zu treffen. –
Ah ja, die bösen Mutable 'List' Iteratoren - Ich erinnere mich an einen Newsgroup-Post mit etwas sah wie ein vernünftiges Stück Code, aber die einige sehr seltsame Ergebnisse aufgrund genau dieser Design-Entscheidung :) Ich werde die Antwort bearbeiten Wie dem auch sei ... Bloße Behauptungen von "es ist nicht wichtig" sind selten eine gute Idee. –