嵌套向量与连续数组的性能影响

时间:2017-08-18 03:02:48

标签: c++ arrays multidimensional-array vector

有没有可靠的测试清楚地显示访问和写入嵌套向量与C ++的内置数组之间的性能差异?我听说使用嵌套(多维)向量通常比访问单个数组中的元素(其中所有元素都存储在连续的内存中)有一些性能开销,但这对我来说似乎只是假设。我还没有看到任何实际显示这些差异的测试。它们重要吗?我确信这取决于场景,但作为一个缺乏经验的程序员,我不太确定这些差异在多大程度上变得显着。

2 个答案:

答案 0 :(得分:6)

这绝对取决于场景,我认为不可能以一般方式回答哪种方法最快。最快的方法是访问模式具有最佳数据局部性的方法 - 这在很大程度上取决于访问模式以及结构在内存中的布局方式,在嵌套向量的情况下依赖于分配器并且可能在编译器之间有很大差异。

我遵循优化的一般规则,即首先以最直接的方式编写内容,然后在证明存在瓶颈时尝试优化。

答案 1 :(得分:3)

嵌套数据和扁平数组之间的运行时差异有两个原因:
缓存行为和间接

  • CPU使用Caches层次结构来避免过于频繁地访问RAM。这利用了大多数内存访问是连续或具有某个时间局部性的事实,即最近访问的内容将很快再次访问。
    这意味着如果嵌套数组的最里面的数组相当大,那么如果以连续的方式迭代值,您会注意到平面数组的差异很小甚至没有差异。这意味着当迭代一系列值时,对于平面数组,最内层循环应迭代连续元素,对于嵌套数组,最内层循环应迭代最内层数组。
  • 但是,如果您的访问模式是随机的,那么时间上最重要的差异就是间接性:
    对于平面数组,使用类似A[(Z * M + Y) * N + X]的内容,因此您可以执行4次算术运算,然后进行内存访问 对于嵌套数组,使用A[Z][Y][X],因此实际上存在三个相互依赖的内存访问:在访问A[Z]之前需要知道A[Z][Y],依此类推。由于现代CPU的超标量体系结构,可以并行执行的操作特别有效,相互依赖的操作不是那么多。 所以你有一些算术运算和一侧的内存负载和另一侧的三个相互依赖的负载,这明显更慢。对于嵌套数组,可能在缓存层次结构中找到AA[Z]的某些值的内容Z,但如果嵌套数组足够大,它永远不会完全适合缓存,因此导致多个缓存未命中和内存加载(嵌套),而不是单个缓存未命中和加载(平坦),以便单个随机访问数组。

另见his question,特别是以下较短的答案,以便更详细地讨论缓存(我的回答)和间接(彼得的回答),这也提供了一个例子,其中没有明显的差异嵌套和平面数组(当然在修复索引错误之后;))

因此,如果您想知道它们之间是否存在重大的运行时差异,我的答案是:

  • 如果您进行随机访问,您肯定会注意到多个间接,从而导致嵌套数组的运行时间更长。

  • 如果您进行连续访问,请使用正确的循环排序(最内层循环=最内层数组/平面数组最内层索引)最内层维度多维数组足够大,然后差异可以忽略不计,因为编译器将能够将所有间接移出最里面的循环。