一个简单的多维数组解引用会很慢吗?

Posted

技术标签:

【中文标题】一个简单的多维数组解引用会很慢吗?【英文标题】:Can a simple multi-dimensional array dereference be slow? 【发布时间】:2018-11-13 21:47:16 【问题描述】:

我很难理解我从 gprof 获得的输出。

我有一个围绕二维数组的简单包装类,我需要在内存中连续。

它的构造函数和我用来访问值的方法是:

Array2d::Array2d(int size, double initialValue)
: mSize(size) 
    data = new double *[size];
    data[0] = new double[size * size];

    for (int i = 1; i < size; ++i) 
        data[i] = data[0] + i * size;
    

    for (int i = 0; i < size; ++i) 
        for (int j = 0; j < size; ++j) 
            data[i][j] = initialValue;
        
    



double &Array2d::operator()(int i, int j) 
    return data[i][j];

在我正在处理的数字代码中,这是我从 gprof 获得的一个输出:

  %   cumulative   self              self     total           
 time   seconds   seconds    calls  ms/call  ms/call  name    
 49.33     34.80    34.80 43507867293     0.00     0.00  Array2d::operator()(int, int)
 18.05     47.53    12.73                             jacobi(Array2d&, Array2d&, int, int, double, double, double, int)

我惊讶地发现,几乎 50% 的运行时间都花在了访问数组中的值上。

这个 Array2d 类取代了 std::vector&lt;double&gt; 的使用,这要快得多。

我在这里没有理解什么?

【问题讨论】:

你为什么使用多个指针? 您确定问题出在代码的那部分吗?不是因为你的函数被调用了430亿次吗? (总共不到 35 秒) @Yksisarvinen:数组初始化是超级奇怪,但我认为它实际上可能是有效的。所有元素都连续有一块内存,data 中的每个元素都指向一个“行”,size 分开。奇怪,但它应该可以工作。 那不是多维数组(数组的数组)。它是一个指向数组的指针数组;它们不是同义词。前者可以非常缓存友好;后者不多。但至少背景是连续的,所以有希望。 @MooingDuck 是的,有一段时间没见过这种东西了。 【参考方案1】:

我很惊讶地发现几乎 50% 的运行时间都花在了 访问数组中的值。

如果没有看到您的代码,我们无法对此多说。很容易编写具有更高百分比的单个调用的代码。考虑

int main()  
    while(true) 
        foo(); 
    

分析器会告诉您,将近 100% 的运行时花费在 foo 上。这是否意味着foo 很慢?不,我们不知道。

您从分析器中获得的百分比可以提示您代码中的热点位置。如果您知道 50% 的时间花在一个特定的函数调用上,那么您就知道这是提高性能的一个很好的候选。如果您优化这个函数调用,您可以实现高达 x2 的加速(参见amdahls law)。

另一方面,一个只使用总运行时间 0.1% 的函数可以将速度提高 1000 倍,而不会对总运行时间产生重大影响。

您的元素访问是慢还是快,您只能知道是否实现了第二个变体,将代码中的其他所有内容保持原样并重复分析。导致更高百分比的变体表现更差。

【讨论】:

以上是关于一个简单的多维数组解引用会很慢吗?的主要内容,如果未能解决你的问题,请参考以下文章

Java数组:数组与多维数组

Java浅谈数组之多维数组

在 PHP 中将多维关联数组展平为一维引用数组

指针引用多维数组

序列化包含对核心数据中 NSManagedObjects 的引用的多维数组

Numpy Polyfit 或 X 和 Y 多维数组的任何拟合