Welche Schleife wird in C # / VB.NET / .NET schneller ausgeführt, for
oder foreach
?
Seit ich vor langer Zeit gelesen habe, dass eine for
Schleife schneller funktioniert als eine foreach
Schleife, habe ich angenommen, dass sie für alle Sammlungen, generischen Sammlungen, alle Arrays usw. gilt.
Ich habe Google durchsucht und einige Artikel gefunden, aber die meisten sind nicht schlüssig (Kommentare zu den Artikeln lesen) und offen.
Ideal wäre es, jedes Szenario aufzulisten und die beste Lösung dafür zu finden.
Zum Beispiel (nur ein Beispiel dafür, wie es sein sollte):
- zum Iterieren eines Arrays von mehr als 1000 Zeichenfolgen -
for
ist besser alsforeach
- zum Iterieren über
IList
(nicht generische) Zeichenfolgen -foreach
ist besser alsfor
Einige Referenzen im Internet für das gleiche gefunden:
- Original großartiger alter Artikel von Emmanuel Schanzer
- CodeProject FOREACH Vs. ZUM
- Blog - Zu
foreach
oder nicht zuforeach
, das ist die Frage - ASP.NET-Forum - NET 1.1 C #
for
vs.foreach
[Bearbeiten]
Abgesehen von dem Aspekt der Lesbarkeit interessiere ich mich sehr für Fakten und Zahlen. Es gibt Anwendungen, bei denen die letzte Meile der Leistungsoptimierung eine Rolle spielt.
quelle
foreach
anstelle vonfor
C # zusammengeführt. Wenn Sie hier Antworten sehen, die überhaupt keinen Sinn ergeben, ist das der Grund. Beschuldigen Sie den Moderator, nicht die unglücklichen Antworten.Antworten:
Patrick Smacchia hat über diesen letzten Monat mit den folgenden Schlussfolgerungen gebloggt :
quelle
foreach
als das Durchlaufen eines Arrays mitfor
, und Sie nennen das unbedeutend? Diese Art von Leistungsunterschied könnte für Ihre Anwendung von Bedeutung sein und auch nicht, aber ich würde ihn nicht einfach sofort ablehnen.foreach
s.Zunächst eine Gegenforderung zu Dmitrys (jetzt gelöschter) Antwort . Bei Arrays gibt der C # -Compiler weitgehend denselben Code aus
foreach
wie bei einer äquivalentenfor
Schleife. Das erklärt, warum für diesen Benchmark die Ergebnisse grundsätzlich gleich sind:Ergebnisse:
Als nächstes überprüfen Sie, ob Gregs Aussage über den Sammlungstyp wichtig ist. Ändern Sie das Array in a
List<double>
oben, und Sie erhalten radikal unterschiedliche Ergebnisse. Es ist nicht nur im Allgemeinen erheblich langsamer, sondern foreach wird auch erheblich langsamer als der Zugriff per Index. Trotzdem würde ich foreach fast immer einer for-Schleife vorziehen, bei der der Code einfacher wird - denn Lesbarkeit ist fast immer wichtig, Mikrooptimierung dagegen selten.quelle
List<T>
? Trumpft die Lesbarkeit auch in diesem Fall die Mikrooptimierung?List<T>
Arrays. Die Ausnahmen sindchar[]
undbyte[]
werden häufiger als "Datenblöcke" als als normale Sammlungen behandelt.foreach
Schleifen zeigen eine spezifischere Absicht alsfor
Schleifen .Die Verwendung einer
foreach
Schleife zeigt jedem, der Ihren Code verwendet, dass Sie vorhaben, jedem Mitglied einer Sammlung etwas anzutun, unabhängig von seinem Platz in der Sammlung. Es zeigt auch, dass Sie die ursprüngliche Sammlung nicht ändern (und löst eine Ausnahme aus, wenn Sie dies versuchen).Der andere Vorteil von
foreach
ist, dass es auf jedem funktioniertIEnumerable
, wo esfor
nur Sinn machtIList
, wo jedes Element tatsächlich einen Index hat.Wenn Sie jedoch den Index eines Elements verwenden müssen, sollten Sie natürlich eine
for
Schleife verwenden dürfen. Wenn Sie jedoch keinen Index verwenden müssen, ist es nur unübersichtlich, wenn Sie einen Index haben.Soweit mir bekannt ist, gibt es keine wesentlichen Auswirkungen auf die Leistung. Irgendwann in der Zukunft ist es möglicherweise einfacher, Code so anzupassen, dass
foreach
er auf mehreren Kernen ausgeführt wird, aber das ist im Moment kein Grund zur Sorge.quelle
foreach
.foreach
hat überhaupt nichts mit funktionaler Programmierung zu tun. Es ist völlig ein Imperativ Paradigma der Programmierung. Sie schreiben Dinge, die in TPL und PLINQ geschehen, falsch zuforeach
.foreach
als Äquivalent einerwhile
Schleife definiert). Ich glaube ich weiß, dass sich @ctford bezieht. Die Task Parallel Library ermöglicht es der zugrunde liegenden Sammlung , Elemente in einer beliebigen Reihenfolge bereitzustellen (durch Aufrufen.AsParallel
einer Aufzählung).foreach
macht hier nichts und der Body der Schleife wird auf einem einzelnen Thread ausgeführt . Das einzige, was parallelisiert wird, ist die Erzeugung der Sequenz.foreach
und diefor
Leistung für normale Listen beträgt Bruchteile einer Sekunde für die Iteration über Millionen von Elementen, sodass Ihr Problem sicherlich nicht direkt mit jeder Leistung zusammenhängt, zumindest nicht für einige hundert Objekte. Klingt nach einer kaputten Enumerator-Implementierung in der von Ihnen verwendeten Liste.Jedes Mal, wenn es Streitigkeiten über die Leistung gibt, müssen Sie nur einen kleinen Test schreiben, damit Sie quantitative Ergebnisse verwenden können, um Ihren Fall zu unterstützen.
Verwenden Sie die StopWatch-Klasse und wiederholen Sie aus Gründen der Genauigkeit einige Millionen Mal. (Dies könnte ohne eine for-Schleife schwierig sein):
Die Daumen drücken, um zu zeigen, dass der Unterschied vernachlässigbar ist, und Sie können genauso gut alles tun, was zu dem am besten zu wartenden Code führt
quelle
Es wird immer nah sein. Bei einem Array ist es manchmal
for
etwas schneller, aberforeach
ausdrucksstärker und bietet LINQ usw. Im Allgemeinen bleiben Sie beiforeach
.foreach
Kann in einigen Szenarien zusätzlich optimiert werden. Zum Beispiel kann eine verknüpfte Liste für den Indexer schrecklich sein, aber sie kann schnell vorbei seinforeach
. Tatsächlich bietet der StandardLinkedList<T>
aus diesem Grund nicht einmal einen Indexer an.quelle
LinkedList<T>
es schlanker ist alsList<T>
? Und wenn ich immerforeach
(stattfor
) verwenden werde, bin ich besser dranLinkedList<T>
?List<T>
) nicht benötigt werden . Es ist mehr, dass das Einsetzen / Entfernen billiger ist .Ich vermute, dass es in 99% der Fälle wahrscheinlich nicht signifikant sein wird. Warum sollten Sie also die schnellere anstelle der am besten geeigneten wählen (wie am einfachsten zu verstehen / zu pflegen)?
quelle
Es ist unwahrscheinlich, dass zwischen beiden ein großer Leistungsunterschied besteht. Wie immer, wenn man mit einem "Was ist schneller?" Frage, sollten Sie immer denken "Ich kann das messen."
Schreiben Sie zwei Schleifen, die dasselbe tun, in den Körper der Schleife, führen Sie beide aus und messen Sie sie zeitlich, und sehen Sie, was der Geschwindigkeitsunterschied ist. Tun Sie dies sowohl mit einem fast leeren Körper als auch mit einem Schleifenkörper, ähnlich dem, was Sie tatsächlich tun werden. Versuchen Sie es auch mit dem von Ihnen verwendeten Sammlungstyp, da verschiedene Arten von Sammlungen unterschiedliche Leistungsmerkmale aufweisen können.
quelle
Es gibt sehr gute Gründe, Loops Loops vorzuziehen . Wenn Sie eine Schleife verwenden können, hat Ihr Chef Recht, dass Sie sollten.
foreach
for
foreach
Allerdings durchläuft nicht jede Iteration einfach eine Liste nacheinander. Wenn er es verbietet , ist das falsch.
Wenn ich Sie wäre, würde ich all Ihre natürlichen for-Schleifen in Rekursion verwandeln . Das würde ihn lehren, und es ist auch eine gute mentale Übung für dich.
quelle
for
Schleifen undforeach
Schleifen in Bezug auf die Leistung zu vergleichen ?Jeffrey Richter auf TechEd 2005:
On-Demand-Webcast: http://msevents.microsoft.com/CUI/WebCastEventDetails.aspx?EventID=1032292286&EventCategory=3&culture=en-US&CountryCode=US
quelle
Das ist lächerlich. Es gibt keinen zwingenden Grund, die for-Schleife in Bezug auf die Leistung oder andere zu verbieten.
In Jon Skeets Blog finden Sie einen Leistungsbenchmark und andere Argumente.
quelle
In Fällen, in denen Sie mit einer Sammlung von Objekten arbeiten,
foreach
ist dies besser. Wenn Sie jedoch eine Zahl erhöhen, ist einefor
Schleife besser.Beachten Sie, dass Sie im letzten Fall Folgendes tun können:
Aber es ist sicherlich nicht besser, es hat tatsächlich eine schlechtere Leistung als ein
for
.quelle
Dies sollte Sie retten:
Verwenden:
Für einen größeren Gewinn können Sie drei Delegierte als Parameter verwenden.
quelle
for
normalerweise eine Schleife geschrieben wird, um das Ende des Bereichs auszuschließen (z0 <= i < 10
. B. ).Parallel.For
tut dies auch, um es leicht mit einer gemeinsamenfor
Schleife austauschbar zu halten .Sie können darüber in Deep .NET - Teil 1 Iteration lesen
Es deckt die Ergebnisse (ohne die erste Initialisierung) vom .NET-Quellcode bis zur Demontage ab.
Beispiel: Array-Iteration mit einer foreach-Schleife:
und - Iteration mit foreach-Schleife auflisten:
und das Endergebnis:
quelle
Die Geschwindigkeitsunterschiede in einer
for
- und einer -foreach
Schleife sind winzig, wenn Sie allgemeine Strukturen wie Arrays, Listen usw. durchlaufen und a ausführenLINQ
Abfrage über die Sammlung fast immer etwas langsamer durchführen, obwohl das Schreiben besser ist! Wie die anderen Poster bereits sagten, sollten Sie sich eher für Ausdruckskraft als für eine Millisekunde zusätzliche Leistung entscheiden.Was bisher nicht gesagt wurde, ist, dass eine
foreach
Schleife beim Kompilieren vom Compiler basierend auf der Sammlung optimiert wird, über die sie iteriert. Das heißt, wenn Sie nicht sicher sind, welche Schleife Sie verwenden sollen, sollten Sie dieforeach
Schleife verwenden - sie generiert die beste Schleife für Sie, wenn sie kompiliert wird. Es ist auch besser lesbar.Ein weiterer wichtiger Vorteil der
foreach
Schleife besteht darin, dass bei Änderungen Ihrer Sammlungsimplementierung ( z. B. von intarray
zu a)List<int>
für Ihreforeach
Schleife keine Codeänderungen erforderlich sind:Das Obige ist unabhängig vom Typ Ihrer Sammlung gleich, während in Ihrer
for
Schleife Folgendes nicht erstellt wird, wenn SiemyCollection
von aarray
zu a wechselnList
:quelle
"Gibt es Argumente, mit denen ich ihn davon überzeugen könnte, dass die for-Schleife akzeptabel ist?"
Nein, wenn Ihr Chef so viel Mikromanagement betreibt, dass er Ihnen sagt, welche Programmiersprachenkonstrukte verwendet werden sollen, können Sie wirklich nichts sagen. Es tut uns leid.
quelle
Dies hängt wahrscheinlich von der Art der Auflistung ab, die Sie auflisten, und von der Implementierung des Indexers. Im Allgemeinen ist die Verwendung
foreach
wahrscheinlich ein besserer Ansatz.Es wird auch mit jedem funktionieren
IEnumerable
- nicht nur mit Indexern.quelle
Dies hat die gleichen zwei Antworten wie die meisten "was schneller ist" -Fragen:
1) Wenn Sie nicht messen, wissen Sie es nicht.
2) (Weil ...) Es kommt darauf an.
Dies hängt davon ab, wie teuer die Methode "MoveNext ()" ist, im Vergleich dazu, wie teuer die Methode "this [int index]" für den Typ (oder die Typen) von IEnumerable ist, über den Sie iterieren werden.
Das Schlüsselwort "foreach" ist eine Abkürzung für eine Reihe von Operationen - es ruft GetEnumerator () einmal in der IEnumerable auf, es ruft MoveNext () einmal pro Iteration auf, es führt eine Typprüfung durch und so weiter. Die Kosten für MoveNext () wirken sich am wahrscheinlichsten auf die Leistungsmessungen aus, da diese O (N) Mal aufgerufen werden. Vielleicht ist es billig, aber vielleicht nicht.
Das Schlüsselwort "for" sieht vorhersehbarer aus, aber in den meisten "for" -Schleifen finden Sie so etwas wie "collection [index]". Dies sieht aus wie eine einfache Array-Indizierungsoperation, ist jedoch ein Methodenaufruf, dessen Kosten vollständig von der Art der Sammlung abhängen, über die Sie iterieren. Wahrscheinlich ist es billig, aber vielleicht nicht.
Wenn die zugrunde liegende Struktur der Sammlung im Wesentlichen eine verknüpfte Liste ist, ist MoveNext spottbillig, aber der Indexer hat möglicherweise O (N) -Kosten, wodurch die tatsächlichen Kosten einer "for" -Schleife O (N * N) entstehen.
quelle
Jedes Sprachkonstrukt hat eine geeignete Zeit und einen geeigneten Ort für die Verwendung. Es gibt einen Grund, warum die C # -Sprache vier separate Iterationsanweisungen hat - jede ist für einen bestimmten Zweck da und hat eine angemessene Verwendung.
Ich empfehle, sich mit Ihrem Chef zusammenzusetzen und rational zu erklären, warum eine
for
Schleife einen Zweck hat. Es gibt Zeiten, in denen einfor
Iterationsblock einen Algorithmus klarer beschreibt als eineforeach
Iteration. Wenn dies zutrifft, ist es angebracht, sie zu verwenden.Ich möchte auch Ihren Chef darauf hinweisen - Leistung ist kein Problem und sollte in keiner praktischen Weise ein Problem sein - es geht eher darum, den Algorithmus auf prägnante, aussagekräftige und wartbare Weise auszudrücken. Mikrooptimierungen wie diese verfehlen den Punkt der Leistungsoptimierung vollständig, da jeder echte Leistungsvorteil durch algorithmisches Redesign und Refactoring und nicht durch Loop-Restrukturierung erzielt wird.
Wenn es nach einer rationalen Diskussion immer noch diese autoritäre Sichtweise gibt, liegt es an Ihnen, wie Sie vorgehen sollen. Persönlich würde ich nicht gerne in einem Umfeld arbeiten, in dem rationales Denken entmutigt wird, und würde in Betracht ziehen, bei einem anderen Arbeitgeber in eine andere Position zu wechseln. Ich empfehle jedoch dringend, die Diskussion zu führen, bevor Sie sich aufregen - möglicherweise liegt nur ein einfaches Missverständnis vor.
quelle
Es ist das, was Sie innerhalb der Schleife tun, das die Leistung beeinflusst, nicht das eigentliche Schleifenkonstrukt (vorausgesetzt, Ihr Fall ist nicht trivial).
quelle
Ob
for
ist schneller alsforeach
wirklich nebensächlich. Ich bezweifle ernsthaft, dass die Auswahl eines über das andere einen erheblichen Einfluss auf Ihre Leistung hat.Der beste Weg, um Ihre Anwendung zu optimieren, ist die Profilerstellung des tatsächlichen Codes. Dadurch werden die Methoden ermittelt, die die meiste Arbeit / Zeit ausmachen. Optimieren Sie diese zuerst. Wenn die Leistung immer noch nicht akzeptabel ist, wiederholen Sie den Vorgang.
Generell würde ich empfehlen, sich von Mikrooptimierungen fernzuhalten, da diese selten zu signifikanten Gewinnen führen. Die einzige Ausnahme ist die Optimierung identifizierter Hot-Paths (dh wenn Ihre Profilerstellung einige häufig verwendete Methoden identifiziert, kann es sinnvoll sein, diese umfassend zu optimieren).
quelle
for
ist geringfügig schneller alsforeach
. Ich würde dieser Aussage ernsthaft widersprechen. Das hängt ganz von der zugrunde liegenden Sammlung ab. Wenn eine verknüpfte Listenklasse einem Indexer einen ganzzahligen Parameter zur Verfügung stellt, würde ich erwarten, dass einefor
Schleife O (n ^ 2) ist, währendforeach
O (n) erwartet wird.for
und eine Indexer-Suche mit der Verwendungforeach
von selbst. Ich denke, die Antwort von @Brian Rasmussen ist richtig, dass sie, abgesehen von der Verwendung mit einer Sammlung,for
immer etwas schneller sein wird alsforeach
. Außerdem istfor
eine Sammlungssuche jedoch immer langsamer alsforeach
von selbst.for
Anweisung verwenden. Eine einfachefor
Schleife mit einer ganzzahligen Steuervariablen ist nicht vergleichbar mitforeach
, also ist das raus. Ich verstehe, was @Brian bedeutet und es ist richtig, wie Sie sagen, aber die Antwort kann irreführend sein. Betreff: Ihr letzter Punkt: Nein, tatsächlich istfor
OverList<T>
immer noch schneller alsforeach
.Die beiden laufen fast genauso. Schreiben Sie einen Code, um beide zu verwenden, und zeigen Sie ihm dann die IL. Es sollte vergleichbare Berechnungen anzeigen, dh keinen Leistungsunterschied.
quelle
for hat eine einfachere Logik zu implementieren, so dass es schneller als foreach ist.
quelle
Wenn Sie sich nicht in einem bestimmten Prozess zur Geschwindigkeitsoptimierung befinden, würde ich sagen, verwenden Sie die Methode, die den am einfachsten zu lesenden und zu pflegenden Code erzeugt.
Wenn bereits ein Iterator eingerichtet ist, wie bei einer der Auflistungsklassen, ist foreach eine gute und einfache Option. Und wenn es sich um einen ganzzahligen Bereich handelt, den Sie iterieren, ist for wahrscheinlich sauberer.
quelle
Jeffrey Richter sprach kürzlich in einem Podcast über den Leistungsunterschied zwischen for und foreach: http://pixel8.infragistics.com/shows/everything.aspx#Episode:9317
quelle
In den meisten Fällen gibt es wirklich keinen Unterschied.
Normalerweise müssen Sie foreach immer verwenden, wenn Sie keinen expliziten numerischen Index haben, und Sie müssen immer foreach verwenden, wenn Sie keine iterierbare Sammlung haben (z. B. Iteration über ein zweidimensionales Array-Gitter in einem oberen Dreieck). . In einigen Fällen haben Sie die Wahl.
Man könnte argumentieren, dass es etwas schwieriger sein kann, for-Schleifen zu pflegen, wenn magische Zahlen im Code erscheinen. Sie sollten sich zu Recht darüber ärgern, dass Sie keine for-Schleife verwenden können und stattdessen eine Sammlung oder ein Lambda verwenden müssen, um eine Untersammlung zu erstellen, nur weil for-Schleifen verboten wurden.
quelle
Es scheint ein bisschen seltsam, die Verwendung einer for-Schleife völlig zu verbieten.
Es ist ein interessanter Artikel hier , die eine Menge der Leistungsunterschiede zwischen den beiden Schleifen abdeckt.
Ich persönlich würde sagen, dass foreach für Schleifen etwas besser lesbar ist, aber Sie sollten das Beste für den jeweiligen Job verwenden und keinen extra langen Code schreiben müssen, um eine foreach-Schleife einzuschließen, wenn eine for-Schleife besser geeignet ist.
quelle
Ich fand die
foreach
Schleife, dieList
schneller durchlief . Siehe meine Testergebnisse unten. Im folgenden Code iteriere ich einearray
Größe der Größen 100, 10000 und 100000 separat mitfor
undforeach
loop, um die Zeit zu messen.AKTUALISIERT
Nach dem @ jgauffin-Vorschlag habe ich den @ johnskeet-Code verwendet und festgestellt, dass die
for
Schleife mitarray
schneller ist als die folgende.Siehe meine Testergebnisse und Code unten,
quelle
Sie können wirklich mit seinem Kopf schrauben und stattdessen einen IQueryable .foreach-Verschluss anstreben:
quelle
myList.ForEach(Console.WriteLine)
.Ich würde nicht erwarten, dass jemand einen "großen" Leistungsunterschied zwischen den beiden findet.
Ich denke, die Antwort hängt davon ab, ob die Sammlung, auf die Sie zugreifen möchten, eine schnellere Implementierung des Indexerzugriffs oder eine schnellere Implementierung des IEnumerator-Zugriffs aufweist. Da IEnumerator häufig den Indexer verwendet und nur eine Kopie der aktuellen Indexposition enthält, würde ich erwarten, dass der Enumeratorzugriff mindestens so langsam oder langsamer ist als der direkte Indexzugriff, jedoch nicht viel.
Natürlich berücksichtigt diese Antwort keine Optimierungen, die der Compiler möglicherweise implementiert.
quelle
Beachten Sie, dass die for-Schleife und die foreach-Schleife nicht immer gleichwertig sind. Listenaufzähler lösen eine Ausnahme aus, wenn sich die Liste ändert, aber Sie erhalten diese Warnung nicht immer mit einer normalen for-Schleife. Möglicherweise erhalten Sie sogar eine andere Ausnahme, wenn sich die Liste zum falschen Zeitpunkt ändert.
quelle