.Net/C# Loop Performance Test (FOR, FOREACH, LINQ, & Lambda)

There's a lot of new syntax. I started to wonder: do these cuties perform? I tried it out and these are my results.

FOR loop

The traditional FOR loop has been the performance champion. Its cryptic syntax has foiled developers resorting to the FOR snippet or turning to FOREACH. But does FOR still compete?

FOREACH loop

Visual Basic invented the FOREACH flow operator. If you have ever forgotten RecordSet.MoveNext() you know how lovely FOREACH is. FOREACH has never outperformed FOR, but it's simplified syntax has made it a favorite among developers. How does it perform in the new syntax landscape?

LIST.FOREACH loop

In the .Net Framework v2.0 the FOREACH delegate was delivered with the new LIST object. This allowed developers to iterate a list without the clutter of a FOREACH loop. Isn't that handy? I understand using delegates with SORT, but I am skeptical of the FOREACH. How does it perform?

LINQ "loop"

LINQ is the Language Integrated Query. It allows developers to put "backwards" SQL in their code. It can iterate, filter, and join enumerable lists. It's powerful. I like it. It has promise. But I was anxious to see how this new developer candy stacked up against the classic loop operators.

LAMBDA => "loop"

Lambda's cryptic syntax has many developers scratching their head. Its steep learning curve is no joke. Most developers (like me) can't separate its purpose from LINQ. However, language complexity is a matter of familiarity. Does this complexity pay off when it comes to performance? Let's take a closer look.

And here are my results:

Note: this is Framework 3.5 SP0 - to be fair.

image

Those are the raw numbers; here are the pretty pictures.

image

Conclusion:

The new syntax stacks up nicely. Clearly LINQ and Lambda can accomplish more complex solutions than a simple loop. However, in this simple scenario they are "just as" good. That's nice.

NOTE: this is an update from my previous post where the numbers were flawed because of a bug in the code. Sorry if you noticed that.

Here's the code I used to test:

This is a simple little console project.

Run it yourself if you doubt the numbers.

static void Test()
{
System.Diagnostics.Stopwatch _Stopwatch =
new System.Diagnostics.Stopwatch();
int _Repeat = 100;

// setup the source list we will iterate

List<int> _List = new List<int>();
for (int i = 0; i < 1000000; i++)
_List.Add(i);

// for

_Stopwatch.Reset();
_Stopwatch.Start();
List<int> _HoldFor;
for (int i1 = 0; i1 < _Repeat; i1++)
{
_HoldFor = new List<int>();
for (int i2 = 0; i2 < _List.Count - 1; i2++)
if (_List[i2] % 2 == 0)
_HoldFor.Add(_List[i2]);
}
_Stopwatch.Stop();
Console.WriteLine("for:\r\n "
+ _Stopwatch.Elapsed.TotalMilliseconds.ToString());

// foreach

_Stopwatch.Reset();
_Stopwatch.Start();
List<int> _HoldForEach;
for (int i1 = 0; i1 < _Repeat; i1++)
{
_HoldForEach = new List<int>();
foreach (int i2 in _List)
if (i2 % 2 == 0)
_HoldForEach.Add(i2);
}
_Stopwatch.Stop();
Console.WriteLine("foreach:\r\n "
+ _Stopwatch.Elapsed.TotalMilliseconds.ToString());

// delegate foreach

_Stopwatch.Reset();
_Stopwatch.Start();
List<int> _HoldForEachDelegate;
for (int i1 = 0; i1 < _Repeat; i1++)
{
_HoldForEachDelegate = new List<int>();
_List.ForEach(delegate(int i)
{
if (i % 2 == 0)
_HoldForEachDelegate.Add(i);
});
}
_Stopwatch.Stop();
Console.WriteLine("list.foreach:\r\n "
+ _Stopwatch.Elapsed.TotalMilliseconds.ToString());

// linq

_Stopwatch.Reset();
_Stopwatch.Start();
for (int i1 = 0; i1 < _Repeat; i1++)
{
var _x = from integer in _List
where integer % 2 == 0
select integer;
}
_Stopwatch.Stop();
Console.WriteLine("linq:\r\n "
+ _Stopwatch.Elapsed.TotalMilliseconds.ToString());

// lambda

_Stopwatch.Reset();
_Stopwatch.Start();
for (int i1 = 0; i1 < _Repeat; i1++)
{
var _x = _List.Where(i => i % 2 == 0);
}
_Stopwatch.Stop();
Console.WriteLine("lambda:\r\n "
+ _Stopwatch.Elapsed.TotalMilliseconds.ToString());

Console.WriteLine(string.Empty);
}

0 comments:

Post a Comment