I wrote the following to test the performance of using foreach
vs LINQ
:
private class Widget
{
public string Name { get; set; }
}
static void Main(string[] args)
{
List<Widget> widgets = new List<Widget>();
int found = 0;
for (int i = 0; i <= 500000 - 1; i++)
widgets.Add(new Widget() { Name = Guid.NewGuid().ToString() });
DateTime starttime = DateTime.Now;
foreach (Widget w in widgets)
{
if (w.Name.StartsWith("4"))
found += 1;
}
Console.WriteLine(found + " - " + DateTime.Now.Subtract(starttime).Milliseconds + " ms");
starttime = DateTime.Now;
found = widgets.Where(a => a.Name.StartsWith("4")).Count();
Console.WriteLine(found + " - " + DateTime.Now.Subtract(starttime).Milliseconds + " ms");
Console.ReadLine();
}
I get something like following output:
31160 - 116ms 31160 - 95 ms
In every run, LINQ outperforms foreach by around 20%. It was my understanding that the LINQ extension methods used standard c# under the covers.
So why is LINQ faster in this case?
EDIT:
So I changed my code to use stopwatch instead of datetime and still get the same results. If I run the LINQ query first then my results show LINQ to be about 20% slower then foreach. This has to be some sort of JIT warmnup issue. My question is how do I compensate for JIT warmup in my test case?
I did some profiling a while back, comparing the following:
LINQ to Objects with/without Regex
Lambda Expressions with/without Regex
Traditional iteration with/without Regex
What I found out was that LINQ, Lambda and Traditional iteration were pretty much the same always, but the real timing difference was in the Regex expressions. Only adding the Regex made the evaluation slower (a LOT slower). (Details here: http://www.midniteblog.com/?p=72)
What you are seeing above is probably due to the fact that you are doing both tests in the same code block. Try commenting one out, timing it, then commenting the other out. Also, make sure you are running a release build, not in the debugger.
It's because you do not have a warmup. If you reverse your cases you will get excatly the opposit result:
Start adding a warmup and use a stopwatch for better timing.
Running the test with warmup:
result: