Siehe auch foreach: Ist die Reihenfolge festgelegt?
Hallo Leute,
ich habe eine generische Liste:
public static List<InsightCam> Cameras = new List<InsightCam>();
InsightCam ist eine Klasse die ich geschrieben habe. Diese befülle ich beim Laden der Form.
Wenn ich nun alle Elemente durchgehen will, welche schleife ist schneller?
A: Die normale For-Schleife?
int iNumOfCams = Cameras.Count;
for (int i = 0; i < iNumOfCams; i++)
{
//...
}
B: Die Foreach-Schleife?
foreach (InsightCam var in Cameras)
{
//...
}
Wer hat das schon mal gemessen? Teilt mit mir euer Wissen 🙂
Danke!
Steffen
Hallo steffen_dec
Wieso misst du es nicht einmal mit einer StopWatch?
Meiner Logik nach müsste eine for-schleife schneller sein.
meiner logik nach müsste eine forschleife bei eher wenigen listelementen geringfügig bis unmessbar schneller sein und bei vielen listelementen generell unmessbar schneller.
fakt ist: es ist absolut unwichtig, da beide recht perfomant sind. wenn es überhaupt einen unterschied gibt, dann liegt er in so einem verschwindend geringen beriech, das man das sowieso mit frameworkmitteln (z.B. stopwatch) nicht messen kann.
Hallo steffen_dec,
fakt ist: es ist absolut unwichtig, da beide recht perfomant sind.
und um das noch zu ergänzen. Der evtl. minimale Performacegewinn, wiegt keinesfalls die Vorteile von foreach hinsichtlich besserer Lesbarkeit und geringerer Fehleranfälligkeit auf.
herbivore
Hallo,
Danke für eure Antworten.
Ich habe es mit 12 Elementen gemessen, die for-Schleife ist ein Tick schneller (was sich natürlich nicht bemerkbar macht...)
Ich habe es nun auf die normale FOR-Schleife umgestellt.
tut mir leid aber das kann ich nciht einfach so stehen lassen.
performance ist KEIN grund zwischen for und foreach zu entscheiden, da der unterschied im unmessbaren bereich fällt. (vor allem bei 12 elementen ist der unterschied DEFINITV NICHT MESSBAR). der unterschied den du festgestellt hast, nennt man messungenauigkeit.
man nimmt foreach, wenn man die collection nicht verändern möchte und man nimmt for, wenn man die collection verändern möchte oder wenn man z.b. nur jedes 2. objekt braucht oder jegliche andere abwandlung eines nicht geradlinig iterativen zugriffes.
mehr gibt es zu dem thema nicht zu schreiben.
Hallo
Meine Frage lautet: Bringt es etwas die Obergrenze der for-Schleife außerhalb des Schleifenkopf zu schreiben. Ich finde das unübersichtilich. gehe ich recht ind er Annahme, dass dies keinen gewinnbringenden Geschwindigkeitszuwachs ergibt.
chrische
gehe ich recht in der Annahme, dass dies keinen gewinnbringenden Geschwindigkeitszuwachs ergibt.
Keinen merkbaren jedenfalls.
Etwas zur foreach-Schleife möchte ich noch sagen: Ich bin eigentlich ein foreach-Schleifen Fan, es gibt für mich nur zwei Hauptgründe keine zu benutzen:*spezielle Reihenfolge beim Durchlaufen *ich muss wissen im wie vielten Durchlauf ich mich befinde
Lg
Preli
Hallo, in diesem Blog http://diditwith.net/2006/10/05/PerformanceOfForeachVsListForEach.aspx
wurde ein ganz netter Vergleich gemacht. Ich habe mir mal die Mühe gemacht und die verschiedenen Arten von Schleifen im IL angesehn:
.method private hidebysig static void TestListFor() cil managed
{
// Code size 30 (0x1e)
.maxstack 2
.locals init ([0] int64 totalValue,
[1] int32 i)
IL_0000: ldc.i4.0
IL_0001: conv.i8
IL_0002: stloc.0
IL_0003: ldc.i4.0
IL_0004: stloc.1
IL_0005: br.s IL_0010
IL_0007: ldloc.0
IL_0008: ldloc.1
IL_0009: conv.i8
IL_000a: add
IL_000b: stloc.0
IL_000c: ldloc.1
IL_000d: ldc.i4.1
IL_000e: add
IL_000f: stloc.1
IL_0010: ldloc.1
IL_0011: ldsfld class [mscorlib]System.Collections.Generic.List`1<int32> ForEachTest.Program::g_IntList
IL_0016: callvirt instance int32 class [mscorlib]System.Collections.Generic.List`1<int32>::get_Count()
IL_001b: blt.s IL_0007
IL_001d: ret
} // end of method Program::TestListFor
.method private hidebysig static void TestListForEach() cil managed
{
// Code size 55 (0x37)
.maxstack 2
.locals init ([0] int64 totalValue,
[1] int32 i,
[2] valuetype [mscorlib]System.Collections.Generic.List`1/Enumerator<int32> CS$5$0000)
IL_0000: ldc.i4.0
IL_0001: conv.i8
IL_0002: stloc.0
IL_0003: ldsfld class [mscorlib]System.Collections.Generic.List`1<int32> ForEachTest.Program::g_IntList
IL_0008: callvirt instance valuetype [mscorlib]System.Collections.Generic.List`1/Enumerator<!0> class [mscorlib]System.Collections.Generic.List`1<int32>::GetEnumerator()
IL_000d: stloc.2
.try
{
IL_000e: br.s IL_001d
IL_0010: ldloca.s CS$5$0000
IL_0012: call instance !0 valuetype [mscorlib]System.Collections.Generic.List`1/Enumerator<int32>::get_Current()
IL_0017: stloc.1
IL_0018: ldloc.0
IL_0019: ldloc.1
IL_001a: conv.i8
IL_001b: add
IL_001c: stloc.0
IL_001d: ldloca.s CS$5$0000
IL_001f: call instance bool valuetype [mscorlib]System.Collections.Generic.List`1/Enumerator<int32>::MoveNext()
IL_0024: brtrue.s IL_0010
IL_0026: leave.s IL_0036
} // end .try
finally
{
IL_0028: ldloca.s CS$5$0000
IL_002a: constrained. valuetype [mscorlib]System.Collections.Generic.List`1/Enumerator<int32>
IL_0030: callvirt instance void [mscorlib]System.IDisposable::Dispose()
IL_0035: endfinally
} // end handler
IL_0036: ret
} // end of method Program::TestListForEach
.method private hidebysig static void TestListForEachCall() cil managed
{
// Code size 37 (0x25)
.maxstack 4
.locals init ([0] class ForEachTest.Program/'<>c__DisplayClass4' 'CS$<>8__locals5')
IL_0000: newobj instance void ForEachTest.Program/'<>c__DisplayClass4'::.ctor()
IL_0005: stloc.0
IL_0006: ldloc.0
IL_0007: ldc.i4.0
IL_0008: conv.i8
IL_0009: stfld int64 ForEachTest.Program/'<>c__DisplayClass4'::totalValue
IL_000e: ldsfld class [mscorlib]System.Collections.Generic.List`1<int32> ForEachTest.Program::g_IntList
IL_0013: ldloc.0
IL_0014: ldftn instance void ForEachTest.Program/'<>c__DisplayClass4'::'<TestListForEachCall>b__3'(int32)
IL_001a: newobj instance void class [mscorlib]System.Action`1<int32>::.ctor(object,
native int)
IL_001f: callvirt instance void class [mscorlib]System.Collections.Generic.List`1<int32>::ForEach(class [mscorlib]System.Action`1<!0>)
IL_0024: ret
} // end of method Program::TestListForEachCall
Leider kann ich die Ergebnisse mit dem PC nicht nachprüfen, da dieser PC seltsame WErte liefert bei Tests. Werde das aber zu Hause an meinem E6700 tun und dann hier berichten.
Generell scheint es so als wäre for ohne count am schnellsten gefolgt von List<T>.ForEach. Das normale foreach scheint am langsamsten zu sein. Für eine genaue IL Code Analyse hab ich keine Zeit gerade, aber hole das gerne später nach.
Achso generell sind IL Code Analysen problematisch, da noch ein Compiler den IL Code übersetzt. Schönes Beispiel sind nicht virtuelle Eigenschaften die nur auf ein privates Feld zugreifen, sonst nichts. Diese werden vom Compiler durch inline ersetzt, davon sieht man aber im IL Code nichts!
Gruß,
Therion
Siehe auch foreach: Ist die Reihenfolge festgelegt?