byte[,] arr = new byte[10, 10];下面这种写法是交错数组 (Jagged Array),就是数组里面套着数组
byte[][] arr = new byte[10][];具体区别请看文末的参考资料~
const int COUNT = 32, SIZE = 32 << 20;这里用了移位操作,32左移20位就是在32的二进制数后面补20个0,相当于 32*2^20,只是用来定义一个比较大的数,现在的电脑性能太强了,小一点的数组复制起来太快了,看不出区别。接着定义几个数组,这里写了五组一维数组,每个不同的数组拷贝方法测试用不同的数组,这样可以避免CPU缓存。
private 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], dSource = new byte[SIZE], dTarget = new byte[SIZE], eSource = new byte[SIZE], eTarget = new byte[SIZE];然后把这几个数组拷贝方法都测试一下。
Linq: array.Select(x=>x).ToArray() Array.Copy() Buffer.BlockCopy() Buffer.MemoryCopy()四 Clone 方式
static void TestArrayClone() { var sw = Stopwatch.StartNew(); sw.Start(); for (var i = 0; i < COUNT; i++) { dTarget = (byte[])dSource.Clone(); } sw.Stop(); Console.WriteLine("Array.Clone: {0:N0} ticks, {1} ms", sw.ElapsedTicks, sw.ElapsedMilliseconds); }这里用了 Stopwatch 来记录执行时间,后面的其他拷贝方法里面也有,等会用这个计算出来的 ticks 和毫秒,可以比较不同实现的性能差距。
eTarget = eSource.Select(x => x).ToArray();
六 Array.Copy()
使用静态方法 Array.Copy() 来实现数组复制
提示:性能是不错的,使用也方便Array.Copy(cSource, cTarget, SIZE);或者用另一个重载,可以分别指定两个数组的偏移值
Array.Copy(cSource, 0, cTarget, 0, SIZE);
七 Buffer.BlockCopy()
Buffer 类是用来操作基本类型数组的
Manipulates arrays of primitive types.代码如下
Buffer.BlockCopy(bSource, 0, bTarget, 0, SIZE);
跟上面的 Array.Copy 第二个重载一样,需要分别指定两个数组的偏移值
八. Buffer.MemoryCopy()
这个是 unsafe 方法,需要用到指针 😀 理论上是性能最好的,我最喜欢的就是这个方法(逼格高)。使用 unsafe 代码,请先在编译选项里面开启 allow unsafe code 选项。这个 MemoryCopy 方法的函数签名是这样的:static unsafe void TestBufferMemoryCopy() { var sw = Stopwatch.StartNew(); fixed (byte* pSrc = fSource, pDest = fTarget) { for (int i = 0; i < COUNT; i++) { Buffer.MemoryCopy(pSrc, pDest, SIZE, SIZE); } } // 堆代码 duidaima.com Console.WriteLine("Buffer.MemoryCopy (2d): {0:N0} ticks, {1} ms", sw.ElapsedTicks, sw.ElapsedMilliseconds); }然后,我在搜索资料的过程中还发现了有人用了 Buffer.Memcpy 这个方法,但这个是 internal 方法,没有开放,得用黑科技去调用,我折腾了很久,终于搞出了调用非公开方法的代码
unsafe delegate void Memcpy(byte* src, byte* dest, int len); internal class Program { private static Memcpy memcpy; static Program() { var methodInfo = typeof(Buffer).GetMethod( "Memcpy", BindingFlags.Static | BindingFlags.NonPublic, null, new Type[] { typeof(byte*), typeof(byte*), typeof(int) }, null ); if (methodInfo == null) { Console.WriteLine("init failed! method is not found."); return; } memcpy = (Memcpy)Delegate.CreateDelegate(typeof(Memcpy), methodInfo); } }实际测试这个 Memcpy 和 MemoryCopy 的性能是差不多的,看了一下.NetCore的源码,果然,这俩个的实现基本是一样的
// Used by ilmarshalers.cpp internal static unsafe void Memcpy(byte* dest, byte* src, int len) { Debug.Assert(len >= 0, "Negative length in memcpy!"); Memmove(ref *dest, ref *src, (nuint)(uint)len /* force zero-extension */); }另一个
public static unsafe void MemoryCopy(void* source, void* destination, long destinationSizeInBytes, long sourceBytesToCopy) { if (sourceBytesToCopy > destinationSizeInBytes) { ThrowHelper.ThrowArgumentOutOfRangeException(ExceptionArgument.sourceBytesToCopy); } Memmove(ref *(byte*)destination, ref *(byte*)source, checked((nuint)sourceBytesToCopy)); }这俩最终都是调用的 Memmove 这个方法,区别就是这俩方法的参数不一样了。