Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How does Array.ForEach() compare to standard for loop in C#?

I pine for the days when, as a C programmer, I could type:

memset( byte_array, '0xFF' );

and get a byte array filled with 'FF' characters. So, I have been looking for a replacement for this:

for (int i=0; i < byteArray.Length; i++)
{
    byteArray[i] = 0xFF;
}

Lately, I have been using some of the new C# features and have been using this approach instead:

Array.ForEach<byte>(byteArray, b => b = 0xFF);

Granted, the second approach seems cleaner and is easier on the eye, but how does the performance compare to using the first approach? Am I introducing needless overhead by using Linq and generics?

Thanks, Dave

like image 606
DaveN59 Avatar asked Mar 25 '10 19:03

DaveN59


3 Answers

Array.ForEach<byte>(byteArray, b => b = 0xFF);

This doesn't do anything. It's setting a copy of each byte to 0xFF, it never gets set in the array.

For an easier way to do this, you could try

Enumerable.Repeat((byte)0xFF, someCount).ToArray();

to initialize your array

Repeat will definitely be slower than your for loop. According to the link posted by CAbbott in a comment, it's about 10.5 seconds slower (12.38 vs 1.7) on an array with over a million items, but that isn't a big difference if you're only doing it a few times with small arrays.

You could write a simple method that will be quicker than Repeat and ToArray because you can know the length of the array before you start filling it.

  public static T[] GetPreFilledArray<T>(T fillItem, int count)
  {
       var result = new T[count];
       for(int i =0; i < count; i++)
       {
           result[i] = fillItem;
       }
       return result;
  }

  byte[] byteArray = GetPreFilledArray((byte)0xFF, 1000);

That should be a pretty quick option, as it's basically what you're doing now.

like image 192
Mike Avatar answered Nov 10 '22 08:11

Mike


The second method uses a delegate to set each byte, this means that there is a method call for every byte in the array. That's a lot of overhead just to set a byte.

The plain loop on the other hand gets optimised rather well by the compiler. It will determine that the index can not be outside the array, so it will skip the bounds checking.

To clarify: You are not using LINQ at all. The ForEach method is a method in the Array class, and it predates the addition of LINQ.

like image 4
Guffa Avatar answered Nov 10 '22 07:11

Guffa


Buffer.BlockCopy is what I tend to use when I want memset/memcpy type behavior. I would measure the performance and use something like reflector. It may be that internally the language calls the built-in classes, which in turn are thin wrappers around MEMCPY and MEMSET.

like image 1
Digicoder Avatar answered Nov 10 '22 08:11

Digicoder