如何在C#中实现Array.Copy?

时间:2011-07-02 16:35:09

标签: c# arrays

我试着用ILSpy查看C#中Array.Copy的实现,但它没有向我展示实现本身。

我写了一个简单的基准测试,Array.Copy与一个简单的for循环来复制数据。 Array.Copy更快。

如何更快地实施?

谢谢, 吉文

2 个答案:

答案 0 :(得分:25)

反汇编Array类会让你知道这个声明:

[MethodImpl(MethodImplOptions.InternalCall), SecurityCritical, ReliabilityContract(Consistency.MayCorruptInstance, Cer.MayFail)]
internal static extern void Copy(Array sourceArray, int sourceIndex, Array destinationArray, int destinationIndex, int length, bool reliable);

[MethodImpl]属性告诉JIT编译器该方法实际上是在CLR中实现的,用C ++而不是托管语言编写。它查找方法名称表,并检索指向实现该方法的C ++函数的指针,并将其编译为简单的CALL指令。

获取CLR的源代码有点棘手,但SSCLI20版本对于已经存在很长时间且不需要调整的方法非常准确。 Array.Copy()当然有资格。我提到的表在clr \ src \ _vm \ ecall.cpp中定义,与您的问题相关的部分如下所示:

FCFuncStart(gArrayFuncs)
    FCFuncElement("Copy", SystemNative::ArrayCopy)
    FCFuncElement("Clear", SystemNative::ArrayClear)
    FCFuncElement("get_Rank", Array_Rank)
    //  etc...

SystemNative :: ArrayCopy()函数指针将您带到clr \ src \ _vm \ comsystem.cpp。实际的功能太大了,无法复制到这里而不会让你的眼睛睁开,有很多错误检查正在进行中。它寻找一种优化副本的方法,幸运的情况是可以简单地复制数组的元素而不进行转换。这是由名为m_memmove()的函数完成的。您将在同一文件中找到该函数,它在32位版本的CLR中使用。

首先复制单个字节,直到目标地址在4个字节的倍数上对齐。然后它一次复制16个字节,4次复制4次,这些复制很快,因为它们是对齐的。然后它一次复制剩下一个字节的内容。

您现在可以看到为什么它比您自己的循环更快。即使数组元素大小不是4字节宽,它也可以一次移动4个字节。并且它可以在确保复制地址对齐的同时这样做,因为数组元素的物理地址是不可发现的。

答案 1 :(得分:11)

用于编写快速memcpy函数的相同技术:

  • 循环展开
  • 以大块(通常使用SIMD)传输对齐数据
  • CPU缓存提示(SIMD也有帮助)

另见: