Laden...

foreach oder for? was ist schneller?

Erstellt von steffen_dec vor 15 Jahren Letzter Beitrag vor 15 Jahren 6.639 Views
Hinweis von herbivore vor 10 Jahren

Siehe auch foreach: Ist die Reihenfolge festgelegt?

S
steffen_dec Themenstarter:in
322 Beiträge seit 2007
vor 15 Jahren
foreach oder for? was ist schneller?

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

S
142 Beiträge seit 2007
vor 15 Jahren

Hallo steffen_dec

Wieso misst du es nicht einmal mit einer StopWatch?

Meiner Logik nach müsste eine for-schleife schneller sein.

Gelöschter Account
vor 15 Jahren

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.

49.485 Beiträge seit 2005
vor 15 Jahren

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

S
steffen_dec Themenstarter:in
322 Beiträge seit 2007
vor 15 Jahren

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.

Gelöschter Account
vor 15 Jahren

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.

C
489 Beiträge seit 2007
vor 15 Jahren

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

343 Beiträge seit 2007
vor 15 Jahren

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

[- www.saftware.net -](http://www.saftware.net/)
T
56 Beiträge seit 2006
vor 15 Jahren

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

Hinweis von herbivore vor 10 Jahren

Siehe auch foreach: Ist die Reihenfolge festgelegt?