Ich habe versucht, den Unterschied zwischen a for
und a foreach
beim Zugriff auf Listen mit Werttypen und Referenztypen zu messen .
Ich habe die folgende Klasse verwendet, um die Profilerstellung durchzuführen.
public static class Benchmarker
{
public static void Profile(string description, int iterations, Action func)
{
Console.Write(description);
// Warm up
func();
Stopwatch watch = new Stopwatch();
// Clean up
GC.Collect();
GC.WaitForPendingFinalizers();
GC.Collect();
watch.Start();
for (int i = 0; i < iterations; i++)
{
func();
}
watch.Stop();
Console.WriteLine(" average time: {0} ms", watch.Elapsed.TotalMilliseconds / iterations);
}
}
Ich habe double
für meinen Werttyp verwendet. Und ich habe diese 'gefälschte Klasse' erstellt, um Referenztypen zu testen:
class DoubleWrapper
{
public double Value { get; set; }
public DoubleWrapper(double value)
{
Value = value;
}
}
Schließlich habe ich diesen Code ausgeführt und die Zeitunterschiede verglichen.
static void Main(string[] args)
{
int size = 1000000;
int iterationCount = 100;
var valueList = new List<double>(size);
for (int i = 0; i < size; i++)
valueList.Add(i);
var refList = new List<DoubleWrapper>(size);
for (int i = 0; i < size; i++)
refList.Add(new DoubleWrapper(i));
double dummy;
Benchmarker.Profile("valueList for: ", iterationCount, () =>
{
double result = 0;
for (int i = 0; i < valueList.Count; i++)
{
unchecked
{
var temp = valueList[i];
result *= temp;
result += temp;
result /= temp;
result -= temp;
}
}
dummy = result;
});
Benchmarker.Profile("valueList foreach: ", iterationCount, () =>
{
double result = 0;
foreach (var v in valueList)
{
var temp = v;
result *= temp;
result += temp;
result /= temp;
result -= temp;
}
dummy = result;
});
Benchmarker.Profile("refList for: ", iterationCount, () =>
{
double result = 0;
for (int i = 0; i < refList.Count; i++)
{
unchecked
{
var temp = refList[i].Value;
result *= temp;
result += temp;
result /= temp;
result -= temp;
}
}
dummy = result;
});
Benchmarker.Profile("refList foreach: ", iterationCount, () =>
{
double result = 0;
foreach (var v in refList)
{
unchecked
{
var temp = v.Value;
result *= temp;
result += temp;
result /= temp;
result -= temp;
}
}
dummy = result;
});
SafeExit();
}
Ich habe Release
und Any CPU
Optionen ausgewählt , das Programm ausgeführt und die folgenden Zeiten erhalten:
valueList for: average time: 483,967938 ms
valueList foreach: average time: 477,873079 ms
refList for: average time: 490,524197 ms
refList foreach: average time: 485,659557 ms
Done!
Dann habe ich die Optionen Release und x64 ausgewählt, das Programm ausgeführt und die folgenden Zeiten erhalten:
valueList for: average time: 16,720209 ms
valueList foreach: average time: 15,953483 ms
refList for: average time: 19,381077 ms
refList foreach: average time: 18,636781 ms
Done!
Warum ist die x64-Bit-Version so viel schneller? Ich habe einen Unterschied erwartet, aber nichts so Großes.
Ich habe keinen Zugriff auf andere Computer. Könnten Sie dies bitte auf Ihren Maschinen ausführen und mir die Ergebnisse mitteilen? Ich verwende Visual Studio 2015 und habe einen Intel Core i7 930.
Hier ist die SafeExit()
Methode, damit Sie selbst kompilieren / ausführen können:
private static void SafeExit()
{
Console.WriteLine("Done!");
Console.ReadLine();
System.Environment.Exit(1);
}
Wie gewünscht, double?
anstelle von DoubleWrapper
:
Beliebige CPU
valueList for: average time: 482,98116 ms
valueList foreach: average time: 478,837701 ms
refList for: average time: 491,075915 ms
refList foreach: average time: 483,206072 ms
Done!
x64
valueList for: average time: 16,393947 ms
valueList foreach: average time: 15,87007 ms
refList for: average time: 18,267736 ms
refList foreach: average time: 16,496038 ms
Done!
Last but not least: Wenn x86
ich ein Profil erstelle, bekomme ich fast die gleichen Ergebnisse bei der VerwendungAny CPU
.