对于2D数组,Array.Copy()比for循环更快吗?

我最近改变了

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]; } 

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

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

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

Array.Copy()可能不是真的更快吗? 我认为它应该是超级优化的!

根据我自己的经验,我发现在性能方面我无法相信自己的直觉。 因此,我保留了一个快速而肮脏的基准测试应用程序(我称之为“StupidPerformanceTricks”),我用它来测试这些场景。 这是非常宝贵的,因为我已经制作了各种关于性能技巧的令人惊讶和反直觉的发现。 同样重要的是要记住在发布模式下运行基准测试应用程序,而不附加调试器,否则您将无法获得JIT优化,并且这些优化可能会产生显着差异:技术A在调试模式下可能比技术B慢,但在发布模式下显着更快,优化的代码。

也就是说,一般来说,我自己的测试经验表明,如果你的数组是<~32个元素,你可以通过滚动自己的复制循环来获得更好的性能 - 可能是因为你没有方法调用开销,这可能很重要。 但是,如果循环大于~32个元素,则使用Array.Copy()可以获得更好的性能。 (如果您正在复制整数或浮点数或类似的东西,您可能还需要调查Buffer.BlockCopy(),这比小数组的Array.Copy()快10%。)

但所有这一切,真正的答案是,“编写自己的测试,尽可能地匹配这些精确的替代品,用循环包裹它们,给循环足够的迭代,使其至少咀嚼2-3秒的价值CPU,然后自己比较备选方案。“

方式.Net的工作方式,我想在优化的情况下,Array.Copy将避免边界检查。

如果对任何类型的集合执行循环,默认情况下CLR将检查以确保您没有传递集合的末尾,然后JIT将要么必须进行运行时评估,要么发出不能需要检查。 (查看我评论中的文章,了解更多详情)

您可以修改此行为,但通常不会保存那么多。 除非你处于一个紧密执行的内循环中,每一毫秒都是重要的,就是这样。

如果数组很大,我会使用Array.Copy,如果它很小,要么应该执行相同的操作。

我确实认为检查是否会为你创造不同的结果。

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

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

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

在多维数组之间进行复制时,数组的行为类似于长一维数组,其中行(或列)在概念上是端对端放置的。 例如,如果一个数组有三行(或列),每行包含四个元素,则从数组开头复制六个元素将复制第一行(或列)的所有四个元素和第二行的前两个元素(或列)。