【问题标题】:Does initialization of 2D array in c program waste of too much time?c程序中二维数组的初始化是否浪费太多时间?
【发布时间】:2009-12-16 09:26:14
【问题描述】:

我正在编写一个 C 程序,它必须使用 2D 数组来存储先前处理的数据以供以后使用。

这个二维数组的大小为 33x33; matrix[33][33].

我把它定义为一个全局参数,所以它只会被初始化一次。当程序运行时,这个定义会花费很多时间吗?因为我发现我的程序在不使用这个矩阵来存储数据的情况下比以前的版本要慢。

补充:

我将这个矩阵初始化为一个全局参数,如下所示:

int map[33][33];
  1. 在函数 A 之一中,我需要将所有 33x33 数据存储到此矩阵中。
  2. 在另一个函数 B 中,我将从 map[33][33] 中获取 3x3 小矩阵以进行下一步处理。

以上 2 个步骤将重复大约 8000 次。那么,会不会影响程序运行效率呢?

或者,我有另一种猜测,因为最近在程序中添加了几个 if-else 分支语句,所以程序运行得更慢了。

【问题讨论】:

  • 不,不应该,但如果没有更多代码,很难为您提供帮助。
  • 像这样分配内存几乎不需要时间。尝试使用分析器查看所有 CPU 时间都花在了哪里。

标签: c multidimensional-array


【解决方案1】:

你以前是怎么做的?我能想到的唯一问题是,从 33x33 整数矩阵中提取 3x3 子矩阵会导致每次提取子矩阵时出现缓存问题。

在大多数现代机器上,高速缓存线的大小为 64 字节。这对于矩阵的 8 个元素来说已经足够了。因此,对于 3x3 子矩阵的每一行额外的行,您将执行一个新的缓存行获取。如果矩阵经常被敲击,那么矩阵可能主要位于 2 级缓存中(如果足够大,甚至可能位于 1 级缓存中)但是如果您在每个子矩阵获取之间进行大量其他数据计算,那么您每次抓取子矩阵时都会获得 3 次昂贵的缓存线提取。

但即便如此,您也不太可能看到性能上的巨大差异。正如其他地方所述,我们需要查看代码之前和之后的代码,以便能够猜测为什么性能变得更差......

【讨论】:

    【解决方案2】:

    稍微简化一下,C 中有三种变量:静态、自动和动态。

    静态变量存在于程序的整个生命周期中,包括全局变量和使用static 声明的局部变量。它们要么初始化为零(默认值),要么显式初始化数据。如果它们为零,则链接器将它们存储到一个新的内存页面中,操作系统将其初始化为零(这需要很短的时间)。如果它们被显式分配,则链接器将数据放入可执行文件的内存区域,操作系统从那里加载它(这需要将数据从磁盘读取到内存中)。

    自动变量是从堆栈中分配的,如果它们被初始化,每次分配时都会发生这种情况。 (如果不是,它们就没有值,或者它们有一个随机值,因此初始化不会花费时间。)

    动态变量使用malloc分配,你必须自己初始化它们,这又需要一点时间。

    您的减速很可能不是由初始化引起的。为了确保这一点,您应该通过分析您的程序并查看时间花在哪里来衡量它。不幸的是,编译器/链接器/操作系统完成的初始化分析可能很困难,尤其是在程序开始执行之前发生的部分。

    如果您想测量初始化数组所需的时间,您可以编写一个虚拟程序,该程序只包含数组。

    但是,由于 33*33 是一个相当小的数字,要么您的矩阵项非常大,您的计算机非常慢,要么您的 33 比我的大。

    【讨论】:

    • 我的电脑很强大:) 所以我想我的程序应该有问题。
    【解决方案3】:

    不,初始化数组一次(使用任何方法)和不初始化它在运行时没有区别。

    如果您发现两个版本之间存在差异,那一定是由于算法实现的差异(或不同的算法)。

    【讨论】:

      【解决方案4】:

      好吧,我不希望它发生(这样的事情应该花不到一秒钟的时间),但一个简单的方法是简单地在 main() 的开头放置一个 print 语句。

      这样您就可以查看全局、静态变量初始化是否真的导致了这种情况。您最近对程序中的其他内容进行了哪些更改?

      编辑 更清楚地了解需要这么长时间的一种方法是使用像 GDB 这样的调试器或像 GProf 这样的分析器

      【讨论】:

        【解决方案5】:

        如果您的程序在运行期间经常访问矩阵(即使它根本没有被更新),则元素地址的计算将涉及乘以 33。执行 lot这可能会导致您的程序变慢。

        【讨论】:

        • 是的,我的附加部分只是说明了这个问题。谢谢大佬。
        【解决方案6】:

        如果不是在矩阵中,您之前的程序版本是如何存储数据的?如果没有大矩阵,如何读取子矩阵?

        许多答案都谈到了初始化所花费的时间。但我认为这不是问题所在。无论如何,在现代处理器上,初始化这么小的数组只需要几微秒。并且只在程序启动时执行一次。

        如果您需要从任何位置获取子矩阵,可能没有比使用静态二维数组更快的方法了。但是,根据处理器架构,如果数组维度(或仅最后一个维度)是 2 的幂(例如 32、64 等),则访问数组可能会更快,因为这将允许使用移位而不是乘法。

        如果访问的子矩阵不重叠(即您只能访问索引 0、3、6 等),那么使用 3 维或 4 维数组可以加快访问速度

          int  map[11][11][3][3];
        

        这使得每个子矩阵成为一个连续的内存块,可以使用单个块复制命令进行复制。 此外,它可能适合单个缓存行。

        【讨论】:

          【解决方案7】:

          理论上使用 N 维数组不应该有性能差异,因为它们都被编译器解析为连续的内存预留。

          int _1D[1089]; int _2D[33][33]; int _3D[3][11][33];

          应该给出类似的分配/解除分配速度。

          【讨论】:

            【解决方案8】:

            您需要对您的程序进行基准测试。如果您不需要初始化,请不要将变量设为静态,或者(也许)使用malloc() 自己从堆中分配它:

            mystery_type *matrix;
            
            matrix = malloc(33 * 33 * sizeof *matrix);
            

            【讨论】:

              猜你喜欢
              • 2014-08-09
              • 1970-01-01
              • 1970-01-01
              • 2013-04-16
              • 1970-01-01
              • 1970-01-01
              • 2020-10-11
              • 1970-01-01
              • 2012-12-01
              相关资源
              最近更新 更多