Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why is AddRange faster than using a foreach loop?

Tags:

c#

.net

c#-4.0

var fillData = new List<int>(); for (var i = 0; i < 100000; i++)      fillData.Add(i);  var stopwatch1 = new Stopwatch(); stopwatch1.Start();  var autoFill = new List<int>(); autoFill.AddRange(fillData); stopwatch1.Stop();  var stopwatch2 = new Stopwatch(); stopwatch2.Start();  var manualFill = new List<int>();  foreach (var i in fillData)     manualFill.Add(i); stopwatch2.Stop(); 

When I take 4 results from stopwach1 and stopwach2, stopwatch1 has always lower value than stopwatch2. That means addrange is always faster than foreach. Does anyone know why?

like image 647
HB MAAM Avatar asked Mar 23 '12 09:03

HB MAAM


People also ask

Why for loop is faster than foreach?

This foreach loop is faster because the local variable that stores the value of the element in the array is faster to access than an element in the array. The forloop is faster than the foreach loop if the array must only be accessed once per iteration.

Are for each loops faster?

As it turned out, FOREACH is faster on arrays than FOR with length chasing. On list structures, FOREACH is slower than FOR. The code looks better when using FOREACH, and modern processors allow using it. However, if you need to highly optimize your codebase, it is better to use FOR.

Which is better for or foreach in C#?

The difference between for and foreach in C# is that for loop is used as a general purpose control structure while foreach loop is specifically used for arrays and collections. In brief, both helps to execute code repeatedly but foreach loop is more specific to arrays and collections.

Which is better for or foreach?

In cases where you work with a collection of objects, foreach is better, but if you increment a number, a for loop is better.


2 Answers

Potentially, AddRange can check where the value passed to it implements IList or IList<T>. If it does, it can find out how many values are in the range, and thus how much space it needs to allocate... whereas the foreach loop may need to reallocate several times.

Additionally, even after allocation, List<T> can use IList<T>.CopyTo to perform a bulk copy into the underlying array (for ranges which implement IList<T>, of course.)

I suspect you'll find that if you try your test again but using Enumerable.Range(0, 100000) for fillData instead of a List<T>, the two will take about the same time.

like image 92
Jon Skeet Avatar answered Sep 18 '22 13:09

Jon Skeet


If you are using Add, it is resizing the inner array gradually as needed (doubling), from the default starting size of 10 (IIRC). If you use:

var manualFill = new List<int>(fillData.Count); 

I expect it'll change radically (no more resizes / data copy).

From reflector, AddRange does this internally, rather than growing in doubling:

ICollection<T> is2 = collection as ICollection<T>; if (is2 != null) {     int count = is2.Count;     if (count > 0)     {         this.EnsureCapacity(this._size + count);         // ^^^ this the key bit, and prevents slow growth when possible ^^^ 
like image 26
Marc Gravell Avatar answered Sep 16 '22 13:09

Marc Gravell