我试着用ILSpy查看C#中Array.Copy
的实现,但它没有向我展示实现本身。
我写了一个简单的基准测试,Array.Copy与一个简单的for循环来复制数据。 Array.Copy更快。
如何更快地实施?
谢谢, 吉文
答案 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
函数的相同技术:
另见: