Array.Copy()在2D数组中是否比for循环更快?

7

最近我进行了更改

        this.FieldValues = new object[2, fieldValues.GetUpperBound(1) + 1];
        for (int i = 0; i < FieldCount; i++)            
        {
            this.FieldValues[Current, i] = fieldValues[Current, i];
            this.FieldValues[Original, i] = fieldValues[Original, i];
        }

to

        FieldValues = new object[2, fieldValues.GetLength(1)];
        Array.Copy(fieldValues, FieldValues, FieldValues.Length); 

其中Current和Original的值分别为常量0和1。FieldValues是一个字段,fieldValues是一个参数。

在我使用它的地方,我发现Array.Copy()版本更快。但另一位开发人员说他在一个独立的程序中计时了for循环和Array.Copy(),发现for循环更快。

Array.Copy()可能并不比for循环更快吗?我认为它应该被超级优化了!


17
如果你关心性能细节,那么编写简单的基准测试程序非常重要 :) - MattDavey
3
并且了解引擎盖下面发生的事情。 - Damian Leszczyński - Vash
1
我的假设是,Array.Copy 比循环更快,特别是当数组的大小增长时。此外,当您可以选择使用框架方法而不是手动编写自己的代码时...除非您有非常具体和可衡量的要求,否则应始终使用框架方法。 - iDevForFun
2
很可能是完全不相关的。 - H H
1
这并不是无关紧要的。我在一个导致性能问题的情况下运行了代码分析器,并将其确定为最大的热点。在那种情况下,使用Array.Copy()可以明显提高速度,但在独立测试程序中,Array.Copy()似乎输给了for循环。 - PeteAC
3个回答

11

根据我的经验,在性能方面,我不能相信自己的直觉。因此,我会保留一个名为“StupidPerformanceTricks”的快速测试应用程序,用来测试这些情况。这非常有价值,因为我发现了许多关于性能技巧的惊人和违反直觉的发现。同时,记得在没有附加调试器的发布模式下运行基准测试应用程序,否则您将无法获得JIT优化,而这些优化可能会产生重大影响:在调试模式下,技术A可能比技术B慢,但在经过优化的发布模式下,它可能会快得多。

尽管如此,总的来说,根据我的测试经验,如果数组大小小于约32个元素,则通过编写自己的复制循环来获得更好的性能——可能是因为您没有方法调用开销,这可能是相当显著的。然而,如果循环大于约32个元素,则使用Array.Copy()可以获得更好的性能。(如果您正在复制int或float或类似的东西,您可能还需要调查Buffer.BlockCopy(),对于小型数组,该方法比Array.Copy()快约10%。)

但是,总的来说,真正的答案是:“编写与这些精确替代方案尽可能匹配的测试,将它们每个包装在一个循环中,给予足够的迭代次数使其消耗至少2-3秒的CPU时间,然后自己比较这些替代方案。”


5
我猜测在优化的情况下,Array.Copy会避免边界检查,这是由于.Net在内部的工作方式导致的。
如果您对任何类型的集合进行循环处理,默认情况下CLR会检查以确保您没有超出集合的末尾,然后JIT将执行运行时评估或发出不需要检查的代码。 (请参见我的评论中的文章以获取更好的详细信息)
您可以修改此行为,但通常您不会节省太多时间,除非您处于紧密执行的内部循环中,每毫秒都很重要。
如果数组很大,我会使用Array.Copy,如果很小,则两者应该表现相同。
我认为是边界检查导致了您的不同结果。

这是一篇较长的阅读,但这是一篇关于边界检查优化的很棒的 MSDN 博客:http://blogs.msdn.com/b/clrcodegeneration/archive/2009/08/13/array-bounds-check-elimination-in-the-clr.aspx - Russ Clarke

-5

在你的特定示例中,有一个因素可能(理论上)表明for循环更快。

Array.Copy是O(n)操作,而您的for循环是O(n/2),其中n是您矩阵的总大小。

Array.Copy需要遍历您的二维数组中的所有元素,因为:

在多维数组之间复制时,该数组的行(或列)在概念上排成一行长的一维数组。例如,如果一个数组有三行(或列),每行(或列)有四个元素,则从数组开头复制六个元素将复制第一行(或列)的所有四个元素和第二行(或列)的前两个元素。


12
这个回答完全误解了O(n)符号的含义。 - jwg

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接