Once in a while, you come across a problem where you have an array a
and you want to copy its values to array b
. You use a technique you know works best or you use what is commonly suggested in the public forums.
But, have you ever wondered what is the fastest way you can copy an array? Well in this article we will benchmark different ways you can copy an array
Prelude
- I'll be using .Net 7.0
- We will copy values from the 0 index.
- You can find the Complete Source Code here
Setup
I am using BenchmarkDotNet version 0.13.9
, for testing I have 2 arrays Destination
and a function that yields a small array and a big array.
private int[] Destination;
[GlobalSetup]
public void GlobalSetup()
{
Destination = Enumerable.Range(0, 2048).ToArray();
}
public IEnumerable<object> GetIntArray()
{
yield return Enumerable.Range(0, 10).ToArray();
yield return Enumerable.Range(0, 1024).ToArray();
}
We will copy the yielded arrays to the big array
ForLoop
A common way to copy an array is by use of a for loop like so;
[Benchmark]
[ArgumentsSource(nameof(GetIntArray))]
public void ForLoopCopy(int[] array)
{
for (int i = 0; i < array.Length; i++)
{
Destination[i] = array[i];
}
}
If benchmark this test we get this result;
That's fairly quick, I bet we can make it faster.
Array.Copy
Another technique commonly used to copy arrays is Array.Copy
[Benchmark]
[ArgumentsSource(nameof(GetIntArray))]
public void ArrayCopy(int[] array)
{
Array.Copy(array, Destination, array.Length);
}
It's quite simple to set up and how does it fair compared to the for loop?
that is a HUGE Leap, for large arrays we have a 14X improvement, and for small arrays, it's 2x improvement. Let's try another approach
Buffer.BlockCopy
This is also another way you can copy arrays.
[Benchmark]
[ArgumentsSource(nameof(GetIntArray))]
public void BufferBlockCopy(int[] array)
{
Buffer.BlockCopy(array, 0, Destination, 0, array.Length * 4);
}
Why do we multiply the length by 4? Well, BlockCopy copies bytes and int has 4 bytes.
It's not as fast as the ArrayCopy for big arrays but it's roughly 2X slower than the Forloop for small arrays.
Span.CopyTo
Spans are contiguous regions of memory, the elements are tightly packed and aligned in one part of the memory. This means reading data can be much faster.
So lets create one;
[Benchmark]
[ArgumentsSource(nameof(GetIntArray))]
public void SpanCopy(int[] array)
{
array.AsSpan().CopyTo(Destination);
}
Caveate: We have to invoke AsSpan method to cast the array to a Span.
It's performance is quite similar to the Array.Copy
Marshal.Copy
In Marshal copy we have to copy an array from managed memory to an unmanaged memory (IntPtr) and then copy from the unmanaged memory back to managed memory. So the code looks like this.
[Benchmark]
[ArgumentsSource(nameof(GetIntArray))]
public unsafe void MarshalCopy(int[] array)
{
fixed (int* dstPtr = Destination)
{
IntPtr ptr = (IntPtr)dstPtr;
Marshal.Copy(array, 0, ptr, array.Length);
}
}
How does it perform?
Well, it's nearly as fast as Array.Copy()
for both small and large arrays.
Summary
What should you use, it is pretty clear that Array.Copy
or Marshal
or Span
are more than sufficient ways for copying one array to another. You can use which ever approach that meets your needs.
Top comments (0)