Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Any faster way of copying arrays in C#?

Tags:

arrays

c#

copy

I have three arrays that need to be combined in one three-dimension array. The following code shows slow performance in Performance Explorer. Is there a faster solution?

for (int i = 0; i < sortedIndex.Length; i++) {     if (i < num_in_left)     {             // add instance to the left child         leftnode[i, 0] = sortedIndex[i];         leftnode[i, 1] = sortedInstances[i];         leftnode[i, 2] = sortedLabels[i];     }     else     {          // add instance to the right child         rightnode[i-num_in_left, 0] = sortedIndex[i];         rightnode[i-num_in_left, 1] = sortedInstances[i];         rightnode[i-num_in_left, 2] = sortedLabels[i];     }                     } 

Update:

I'm actually trying to do the following:

//given three 1d arrays double[] sortedIndex, sortedInstances, sortedLabels; // copy them over to a 3d array (forget about the rightnode for now) double[] leftnode = new double[sortedIndex.Length, 3]; // some magic happens here so that leftnode = {sortedIndex, sortedInstances, sortedLabels}; 
like image 969
Yang Avatar asked Feb 24 '11 02:02

Yang


People also ask

Can you copy arrays in C?

Copying an array involves index-by-index copying. For this to work we shall know the length of array in advance, which we shall use in iteration. Another array of same length shall be required, to which the array will be copied.

Which method of an array creates a duplicate copy?

arraycopy() clone() creates a new array of the same size, but System. arraycopy() can be used to copy from a source range to a destination range. System.


2 Answers

Use Buffer.BlockCopy. Its entire purpose is to perform fast (see Buffer):

This class provides better performance for manipulating primitive types than similar methods in the System.Array class.

Admittedly, I haven't done any benchmarks, but that's the documentation. It also works on multidimensional arrays; just make sure that you're always specifying how many bytes to copy, not how many elements, and also that you're working on a primitive array.

Also, I have not tested this, but you might be able to squeeze a bit more performance out of the system if you bind a delegate to System.Buffer.memcpyimpl and call that directly. The signature is:

internal static unsafe void memcpyimpl(byte* src, byte* dest, int len) 

It does require pointers, but I believe it's optimized for the highest speed possible, and so I don't think there's any way to get faster than that, even if you had assembly at hand.


Update:

Due to requests (and to satisfy my curiosity), I tested this:

using System; using System.Diagnostics; using System.Reflection;  unsafe delegate void MemCpyImpl(byte* src, byte* dest, int len);  static class Temp {     //There really should be a generic CreateDelegate<T>() method... -___-     static MemCpyImpl memcpyimpl = (MemCpyImpl)Delegate.CreateDelegate(         typeof(MemCpyImpl), typeof(Buffer).GetMethod("memcpyimpl",             BindingFlags.Static | BindingFlags.NonPublic));     const int COUNT = 32, SIZE = 32 << 20;      //Use different buffers to help avoid CPU cache effects     static byte[]         aSource = new byte[SIZE], aTarget = new byte[SIZE],         bSource = new byte[SIZE], bTarget = new byte[SIZE],         cSource = new byte[SIZE], cTarget = new byte[SIZE];       static unsafe void TestUnsafe()     {         Stopwatch sw = Stopwatch.StartNew();         fixed (byte* pSrc = aSource)         fixed (byte* pDest = aTarget)             for (int i = 0; i < COUNT; i++)                 memcpyimpl(pSrc, pDest, SIZE);         sw.Stop();         Console.WriteLine("Buffer.memcpyimpl: {0:N0} ticks", sw.ElapsedTicks);     }      static void TestBlockCopy()     {         Stopwatch sw = Stopwatch.StartNew();         sw.Start();         for (int i = 0; i < COUNT; i++)             Buffer.BlockCopy(bSource, 0, bTarget, 0, SIZE);         sw.Stop();         Console.WriteLine("Buffer.BlockCopy: {0:N0} ticks",             sw.ElapsedTicks);     }      static void TestArrayCopy()     {         Stopwatch sw = Stopwatch.StartNew();         sw.Start();         for (int i = 0; i < COUNT; i++)             Array.Copy(cSource, 0, cTarget, 0, SIZE);         sw.Stop();         Console.WriteLine("Array.Copy: {0:N0} ticks", sw.ElapsedTicks);     }      static void Main(string[] args)     {         for (int i = 0; i < 10; i++)         {             TestArrayCopy();             TestBlockCopy();             TestUnsafe();             Console.WriteLine();         }     } } 

The results:

Buffer.BlockCopy: 469,151 ticks Array.Copy: 469,972 ticks Buffer.memcpyimpl: 496,541 ticks  Buffer.BlockCopy: 421,011 ticks Array.Copy: 430,694 ticks Buffer.memcpyimpl: 410,933 ticks  Buffer.BlockCopy: 425,112 ticks Array.Copy: 420,839 ticks Buffer.memcpyimpl: 411,520 ticks  Buffer.BlockCopy: 424,329 ticks Array.Copy: 420,288 ticks Buffer.memcpyimpl: 405,598 ticks  Buffer.BlockCopy: 422,410 ticks Array.Copy: 427,826 ticks Buffer.memcpyimpl: 414,394 ticks 

Now change the order:

Array.Copy: 419,750 ticks Buffer.memcpyimpl: 408,919 ticks Buffer.BlockCopy: 419,774 ticks  Array.Copy: 430,529 ticks Buffer.memcpyimpl: 412,148 ticks Buffer.BlockCopy: 424,900 ticks  Array.Copy: 424,706 ticks Buffer.memcpyimpl: 427,861 ticks Buffer.BlockCopy: 421,929 ticks  Array.Copy: 420,556 ticks Buffer.memcpyimpl: 421,541 ticks Buffer.BlockCopy: 436,430 ticks  Array.Copy: 435,297 ticks Buffer.memcpyimpl: 432,505 ticks Buffer.BlockCopy: 441,493 ticks 

Now change the order again:

Buffer.memcpyimpl: 430,874 ticks Buffer.BlockCopy: 429,730 ticks Array.Copy: 432,746 ticks  Buffer.memcpyimpl: 415,943 ticks Buffer.BlockCopy: 423,809 ticks Array.Copy: 428,703 ticks  Buffer.memcpyimpl: 421,270 ticks Buffer.BlockCopy: 428,262 ticks Array.Copy: 434,940 ticks  Buffer.memcpyimpl: 423,506 ticks Buffer.BlockCopy: 427,220 ticks Array.Copy: 431,606 ticks  Buffer.memcpyimpl: 422,900 ticks Buffer.BlockCopy: 439,280 ticks Array.Copy: 432,649 ticks 

or, in other words: they're very competitive; as a general rule, memcpyimpl is fastest, but it's not necessarily worth worrying about.

like image 103
user541686 Avatar answered Sep 22 '22 06:09

user541686


You can use Array.Copy.

EDIT

Array.Copy does work for multidimensional arrays: see this topic.

like image 27
Marlon Avatar answered Sep 22 '22 06:09

Marlon