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

Array.Copy是如何在C#中实现的?,c#,arrays,C#,Arrays,我试图用ILSpy在C#中查看Array.Copy的实现,但它没有显示实现本身 我编写了一个简单的基准测试,Array.Copy和一个简单的for循环来复制数据。 数组。复制速度更快 如何更快地实现它 谢谢, Shay编写快速memcpy函数时使用的相同技术: 循环展开 在大数据块中传输对齐的数据(通常使用SIMD) CPU缓存提示(SIMD在这里也有帮助) 另见: 反汇编数组类将使您获得以下声明: [MethodImpl(MethodImplOptions.InternalCall

我试图用ILSpy在C#中查看
Array.Copy
的实现,但它没有显示实现本身

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

如何更快地实现它

谢谢,
Shay

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

  • 循环展开
  • 在大数据块中传输对齐的数据(通常使用SIMD)
  • CPU缓存提示(SIMD在这里也有帮助)
另见:


反汇编数组类将使您获得以下声明:

[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);
< P> > [MeoDimpL]属性告诉JIT编译器,该方法实际上是在CLR中实现的,用C++编写而不是托管语言。它在一个方法名称表中检索一个指向实现该方法的C++函数的指针,并将其编译成一个简单的调用指令。p> 获取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字节。它可以做到这一点,同时确保拷贝地址对齐,因为数组元素的物理地址是不可发现的。

可能是因为,由于数组在内存中是连续的,CLR可以计算需要拷贝的内存大小,然后一次将其全部拷贝,而不是一次只实现一个对象。这是否可能在C#中实现,或者仅在汇编或C/C++中实现?@Shayfaldor:这取决于JIT编译器。例如Microsoft的.NET没有提供这种级别的控制,但可能会使用SIMD指令作为优化的结果。Hmmm说,“这种方法相当于标准C/C++函数memmove,而不是memcpy。”但是,如果我理解正确,它只是逐字节移动整个内存,而不是迭代数组,读取和写入每个键,这节省了很多操作。我说得对吗?@shayfalador:Technqiues可以加速
memcpy
也可以加速
memmove
。是的,CPU一次可以抓取多少字节,而不是单个数组元素,这是其中的一个技巧(这是我的子弹2)。答案很好!非常感谢你。