二维数组访问的性能问题

背景

这是一个基本问题,经常会出现在面试中,考察面试者对内存存储和CPU访问的理解

问题

仔细看下面两段代码,它们运行速度有何差异,为什么?
Version1

using System;

class Program
{
    static void Main()
    {
        int i, j;
        int[,] x = new int[4000, 4000];
        for (i = 0; i < 4000; i++)
        {
            for (j = 0; j < 4000; j++)
            {
                x[j, i] = i + j;
            }
        }
    }
}    

Version2

using System;

class Program
{
    static void Main()
    {
        int i, j;
        int[,] x = new int[4000, 4000];
        for (j = 0; j < 4000; j++)
        {
            for (i = 0; i < 4000; i++)
            {
                x[j, i] = i + j;
            }
        }
    }
}    

答案

C# 语言以及大多数语言中,Version2 速度会比 Version1 快。

为什么?

为什么强调语言,因为不同语言对于多维数组的内存布局方式可能不一样。

主要有行优先和列优先
image

图源 https://en.wikipedia.org/wiki/Row-major_order

大多数编程语言会选择行优先存储,少数则会列优先,比如Fortran。

存储示意如下图:
image

图源 https://craftofcoding.wordpress.com/2017/02/03/column-major-vs-row-major-arrays-does-it-matter/

可以看到二维数组在内存中按照"规则"在内存中的存储。

在读数据的时候,如果数据量特别小,差异自然不大。
但是如果数据量很大的情况下,因为CPU的局部性原理,Version 2会有效的命中Cache,减少CPU读取内存的次数,从而减少运行时间。
image

图源 https://pikuma.com/blog/understanding-computer-cache

Ref

https://stackoverflow.com/questions/9936132/why-does-the-order-of-the-loops-affect-performance-when-iterating-over-a-2d-arra

posted @ 2025-04-03 13:38  talentzemin  阅读(28)  评论(0)    收藏  举报