【问题标题】:Which is the fastest? A boost::multi_array or a std::vector?哪个最快? boost::multi_array 还是 std::vector?
【发布时间】:2013-07-27 02:07:01
【问题描述】:

哪个最快? boost::multi_array 还是 std::vector? 我将(不是恒定的)17.179.869 个元素存储在 3 个维度中,需要在 for 循环中非常快速且非常频繁地访问这些元素。最有表现力的会是什么? std::vector 还是 boost::multi_array

(我不希望它在一秒钟内完成,但我希望它尽可能高效,因为纳秒的差异可以节省大量时间。)

【问题讨论】:

  • 如果您关心,请同时实施并衡量......
  • 取决于您的迭代方式以及是否在 POD 上进行迭代。 std::vector 作为一个扁平数组,如果您在最小维度上迭代并使用指针而不是 [] 或迭代器运算符进行迭代,则很可能是最快的。如果您对元素进行大量处理,这真的不会有太大的不同。
  • @MadScienceDreams:我相信Boost.MultiArray 也存储在一个连续的块中。来自data 访问器的概要: 这将返回一个指向包含数组数据的连续块的开头的指针。 [...]
  • @MadScienceDreams 使用指针而不是普通的 [] 将加载时间从 61 秒增加到 188 秒。
  • @Binero 那是……奇怪。如果您获得一次指针(即 ptr=&arr[0]),然后在迭代期间递增指针(即 ptr++),那么在最坏的情况下性能应该大致相同,但预缓存应该使它变得微不足道。

标签: c++ arrays performance stdvector boost-multi-array


【解决方案1】:

最好的建议是自己进行基准测试。

无论如何,由于您的大小似乎是恒定的,因此还有其他解决方案:

  • 纯 C 数组(例如int data[X][Y][Z]
  • 简单的一维 C 数组,您可以在其中自己计算索引,例如 X*W*H + Y*W + Z,在某些情况下会很方便
  • std::array,它基本上是一个 C++ 数组,其中包含一些来自 STL 集合的语法糖
  • std::vector,我猜这是第一个可以尝试的解决方案
  • boost::multi_array,它旨在支持 N 维数组,因此对于您的目的来说它可能是多余的,但与向量相比可能具有更好的数据局部性。

【讨论】:

  • 问题是大小不是恒定的,这只是我正在测试的值的数量,是总大小的 1/8。
  • 您的意思是boost::multi_array(在您的最后一个要点中)而不是std::multi_array?后者不存在。
  • 就我个人而言,我会建议上面提到的std::arraystd::vector,这样您就不必担心内存以及可能发生的所有讨厌的事情。除此之外,我建议在第二个要点中使用索引策略
  • @wlyles 第二点的索引策略会占用太多性能,因为我需要每个循环中的当前维度。
  • @Binero:如果某些索引没有移动,您当然可以缓存部分计算!
【解决方案2】:

这些库矢量类被设计为易于使用且相对安全。 它们在设计范围内尽可能快,但没有什么能比你自己做的更好(除了手工编码的组装)。 对于您正在谈论的大小(2e10 个元素),我会更关心效率而不是用户友好性。 如果你最里面的循环对每个元素做的计算很少,你会发现索引计算占主导地位, 这建议做一些展开和指针步进。 (也许你可以指望编译器做一些展开,但我不关心也许。)

【讨论】:

    【解决方案3】:

    确定的唯一方法是同时尝试并分析代码。然而,作为一堆想法,这就是我认为你会发现的。

    1. 对于您正在处理的大量元素 (2e10+),对元素的访问不会像将这些元素加载到 cpu 缓存中的缓存压力那样重要。预取器将坐在那里尝试加载这些元素,这将占用大部分时间。
    2. 访问 2(或 3D)非连续 C 数组意味着 CPU 必须从内存的不同部分获取内容。 boost::multi_array 通过在幕后将其存储为连续块来解决这个问题;但这样做有自己的开销。正如@Jack 所说,带有索引的普通一维数组是最好的,即使那样你也可以做一些事情来确保索引最小化。(例如记忆)
    3. 您在循环中所做的工作将显着影响您的时间安排。分支预测器将是最大的贡献者。如果这是一个简单的数学运算,没有 if/else 语句,您可能会获得最佳性能,并且编译器可能会将其优化为 SSE 指令。如果您有复合类型(而不是 int/float/char),那么您将不得不正确布置它们以优化访问。
    4. 我几乎会建议,尝试两者,然后返回一个新的 SO 问题,其中包含您的循环并询问如何优化该部分。几乎总是可以向编译器提供提示,以确保它知道您的意图。

    在一天结束的时候,试试看

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2012-03-07
      • 2017-08-22
      • 2017-12-23
      • 2011-12-15
      • 1970-01-01
      • 1970-01-01
      • 2011-09-17
      • 1970-01-01
      相关资源
      最近更新 更多