Home > .net 3.5, c#, LINQ, Visual Studio 2008 > Comparing ForEach Overheads

Comparing ForEach Overheads

April 16, 2008

I’ve spent a bit of time dinking with foreach this morning while waiting for a customer to respond… and figured I’d put the ForEach extension method to a test.

Using a generic form of the Benchmark utility class, I brought in a heap of data from a database and iterated through it 1 million (1,000,000) times, each time adding the record Id into a generic list.

The benchmark doesn’t include the time to fetch the data or the creation of the list, simply the foreach and method inside the foreach, which is identical in both test cases.

The data source, Report.GetReports, is returning approximately 12,000 records (Report objects, in this case) from an Oracle database; so each ForEach is iterating through those 12,000 records… 1 million times.

Assumptions

  • I expected the ToList() conversion to add a great deal of weight.
  • I expected the standard foreach methodology to fly by.

Results

The results were quite shocking.

As with most technologies or “cool things” like extension methods, there are usually tradeoffs and those are almost always in regards to performance.

And, it is slower… marginally.  I ran the entire battery of tests ten times and all but once the foreach statement came out ahead; however, the margins were usually in the hundredths of seconds.

My assumption that the ToList() would add “a great deal of weight” is a bit off.  While I’m not certain, I am pretty sure that a few milliseconds accounts to the conversion—just not as much as I expected.  Overall, I’m pretty shocked to see the numbers as close as they are.  A bit of that falls to CPU cycles as well; the margin between the two is relatively the same throughout.

Raw Results

Test #0

Ext: 00:00:01.0781181

foreach: 00:00:01.0468683

Test #1

Ext: 00:00:01.1049239

foreach: 00:00:01.1093679

Test #2

Ext: 00:00:01.0937430

foreach: 00:00:01.0781181

Test #3

Ext: 00:00:01.2187422

foreach: 00:00:01.1093679

Test #4

Ext: 00:00:01.2656169

foreach: 00:00:01.0937430

Test #5

Ext: 00:00:01.2343671

foreach: 00:00:01.1874924

Test #6

Ext: 00:00:01.2187422

foreach: 00:00:01.0937430

Test #7

Ext: 00:00:01.3124916

foreach: 00:00:01.0624932

Test #8

Ext: 00:00:01.2499920

foreach: 00:00:01.1718675

Test #9

Ext: 00:00:01.2499920

foreach: 00:00:01.0624932

Here’s the code for the entire test:

var mark = new Benchmark();

var stmt1 = Report.GetReports(teacherId, quarter, year);

 

for (int iteration = 0; iteration < 10; iteration++)

{

var list1 = new List<int>();

var list2 = new List<int>();

mark.Start();

for (int i = 0; i < 1000000; i++)

{

                     stmt1.ToList().ForEach(x => list1.Add(x.Id));

}

mark.Stop();

 

       var extension = mark.ElapsedTime.ToString();

 

mark.Start();

for (int i = 0; i < 1000000; i++)

{

foreach (var x in stmt1)

               {

                     list2.Add(x.Id);

}

}

 

mark.Stop();

       var fe = mark.ElapsedTime.ToString();

 

       Console.WriteLine(“Test #{0}, Ext: {1}, foreach: {2}”,

              iteration, extension, fe);

}

%d bloggers like this: