for oder foreach
-
Hallo!
Ich habe mich vor kurzem mit der Performance-Frage bei der foreach Schleife beschäftigt und ein kleines Testprogramm geschrieben, welches ein int Array und eine List<int> Collection anlegt, diese dann jeweils in mit einer for und einer foreach Schleife durchgeht und den den Wert des derzeitigen Index zu einer Variable addiert (um Zugriff zu simulieren).
Hier sind die Ergebnisse:
ElementAnz: 10000
for array: 3.8831750962762E-05
foreach array: 2.79365114840015E-05for list: 7.48698507771239E-05
foreach list: 8.35301693371644E-05----------------------------------------------------------------------
ElementAnz: 100000for array: 0.000274895273002574
foreach array: 0.000245003205714693for list: 0.000293892100811695
foreach list: 0.00204299708482503----------------------------------------------------------------------
ElementAnz: 1 Millionfor array: 0.00339428614530618
foreach array: 0.00223212726757172for list: 0.00288025433400055
foreach list: 0.00953668692529358----------------------------------------------------------------------
ElementAnz: 10 Millionenfor array: 0.0222863520363622
foreach array: 0.0224609552331372for list: 0.0270947843929885
foreach list: 0.0841674011641144----------------------------------------------------------------------
ElementAnz: 100 Millionenfor array: 30.0141802938642
foreach array: 26.3471765266256for list: 30.2271188097929
foreach list: 34.7332462645392Was mich verblüfft ist, dass foreach bei normalen Arrays offenbar schneller ist als for, bei ListCollections aber weit zurückfällt.
Wie seht ihr die Sache und verwendet ihr foreach in euren Programmen oder nutzt ihr eher nur for?
-
Generell ist foreach langsamer als for, aber ist auch kein Wunder wenn man weiß wie foreach arbeitet. Außerdem könnte ich wetten das foreach bei einfachen Arrays eh zu nem for optimiert wird, da dort nen Enumerator unnötig ist. Auch lässt sich ohne Code eh wenig sagen, wo eventuell noch optimiert wird. Der Jitter ist da ziemlich gut was optimieren angeht. Du lässt es auch im Debugmodus laufen oder?
-
Der Programmcode ist hier:
using System; using System.Collections.Generic; using System.Text; using System.Collections.Specialized; using System.Windows.Forms; using System.IO; namespace ForeachTest { public class Program { static TextWriter Writer; static string[] Buffer; static void Main(string[] args) { int COUNT; StreamReader r = null; if (args.Length > 0) { try { COUNT = int.Parse(args[0]); } catch { return; } } Buffer = new string[5]; Buffer[2] = ""; int[] array = new int[COUNT]; List<int> list = new List<int>(COUNT); for (int i = 0; i < COUNT; ++i) { array[i] = 1; list.Add(1); } DoForTestArray(array); DoForTestList(list); DoForeachTestArray(array); DoForeachTestList(list); Writer = new System.IO.StreamWriter("Results.txt", true); Writer.WriteLine("\n----------------------------------------------------------------------\n"); foreach (string s in Buffer) Writer.WriteLine(s); Writer.Close(); } private static void DoForeachTestArray(int[] list) { int foo = 0; HiPerfTimer timer = new HiPerfTimer(); timer.Start(); foreach (int i in list) { foo += i; } timer.Stop(); Buffer[1] = String.Format("foreach array: \t{0}\t\tElementCount: {1}", timer.Duration, foo); } private static void DoForTestArray(int[] list) { int foo = 0; HiPerfTimer timer = new HiPerfTimer(); timer.Start(); for (int i = 0; i < list.Length; ++i) { foo += list[i]; } timer.Stop(); Buffer[0] = String.Format("for array: \t{0}\t\tElementCount: {1}", timer.Duration, foo); } static void DoForeachTestList(List<int> list) { int foo = 0; HiPerfTimer timer = new HiPerfTimer(); timer.Start(); foreach (int i in list) { foo += i; } timer.Stop(); Buffer[4] = String.Format("foreach list: \t{0}\t\tElementCount: {1}", timer.Duration, foo); } private static void DoForTestList(List<int> list) { int foo = 0; HiPerfTimer timer = new HiPerfTimer(); timer.Start(); for (int i = 0; i < list.Count; ++i) { foo += list[i]; } timer.Stop(); Buffer[3] = String.Format("for list: \t{0}\t\tElementCount: {1}", timer.Duration, foo); } } }
und hier noch der Timercode:
using System; using System.Runtime.InteropServices; using System.ComponentModel; using System.Threading; namespace ForeachTest { internal class HiPerfTimer { [DllImport("Kernel32.dll")] private static extern bool QueryPerformanceCounter(out long lpPerformanceCount); [DllImport("Kernel32.dll")] private static extern bool QueryPerformanceFrequency(out long lpFrequency); private long startTime, stopTime; private long freq; // Constructor public HiPerfTimer() { startTime = 0; stopTime = 0; if (QueryPerformanceFrequency(out freq) == false) { // high-performance counter not supported throw new Win32Exception(); } } // Start the timer public void Start() { // lets do the waiting threads there work Thread.Sleep(0); QueryPerformanceCounter(out startTime); } // Stop the timer public void Stop() { QueryPerformanceCounter(out stopTime); } // Returns the duration of the timer (in seconds) public double Duration { get { return (double) (stopTime - startTime) / (double) freq; } } } }
Bei den Tests habe ich es nicht im Debugmodus laufen lassen. Es war immer ein Release Build, den ich außerhalb von Visual Studio hab laufen lassen.
-
Wie seht ihr die Sache und verwendet ihr foreach in euren Programmen oder nutzt ihr eher nur for?
Es sollte keine Performance-Frage sein, ob for oder foreach. Ganz einfach. Die Unterschiede sind lächerlich und bei einer Anwendung, die mehr macht, als eine Collection zu durchlaufen, irrelevant. Durch eine Collection läuft man, um etwas mit den Elementen zu tun und dieses "tun" ist i.d.R. schon weit aufwändiger.
Und wenn das durchlaufen einer Collection der Flaschenhals ist, dann sollte man sich vielleicht überlegen, ob es nicht besser ist, eine Datenstruktur zu verwenden, die man nicht komplett durchlaufen muss, um das gewünschte zu finden/erreichen.
-
ist, dass es bei einer Liste und random access also liste[i] nicht böse auf die Performance gehr. oder?
Hätte hier eigentlich das foreach klar im Vorteil gesehen.
-
Die "List" ist als ArrayList implementiert.
-
Eigentlich hast du recht, Optimizer, "wirkliche" Schleifen bestehen aus etwas mehr Code als nur einer Addition, sodass der Unterschied zwischen for und foreach nicht mehr so ins Gewicht fällt.