【问题标题】:comparing two vectors, make it more efficient比较两个向量,使其更有效
【发布时间】:2013-04-27 18:39:09
【问题描述】:

使用 kcachegrind 并在调试模式下运行代码,我发现我的程序的瓶颈是比较两个向量的点。

if (v1 == v2) {
  // DO
}

如何提高效率?这样更好吗

if (v1[0] == v2[0]) {
   if (v1 == v2) {
      // DO
   }
}

第一行会过滤掉一些无用的比较。

在此之前我尝试过

if (!v2.empty())
  if (v1 == v2) 
   // DO

但是我发现它们几乎总是不是空的。所以empty()的额外时间也包括在内。

不得不说,向量的大小大多都很小。 2~4个元素。在极少数情况下,它们会扩展到 10 个。

更新: 感谢 Mats Petersson,看来通过在优化模式下编译,还有一些性能改进。

【问题讨论】:

  • 你的向量的value_type是什么?
  • @mahmood 你在说,比较 vector<uint_64t>s 的 2-4 个元素是瓶颈吗?您是否有机会对调试版本进行基准测试,而不是进行优化的发布版本?
  • @mahmood 在 C++ 中,优化,尤其是内联,还有循环展开,在性能方面发挥着重要作用。如果瓶颈是一件微不足道的事情,肯定会受到这些优化的影响,那么对调试版本进行基准测试就毫无意义了。
  • 啊!请关闭调试(如果需要,请保持调试符号打开)以进行性能测量。
  • @mahmood 是的,这可能是个问题,优化可以彻底破坏未优化构建的直接组装。我喜欢称之为微观分析不确定性原则:你不能同时得到原始源代码中瓶颈的确切位置,以及优化代码中真正的瓶颈。

标签: c++ performance vector


【解决方案1】:

如果它真的是你程序的瓶颈,你应该重构你的设计。比较两个范围总是在 O(N) 中运行。

如果您真的想保留您的设计,那么您可以选择:保留这些性能或进行猜测。您可能想要寻找 变化最大的向量部分。当然,如果你有完全随机的 push_backs,那就不值得了。然后你就可以开始测试这些元素了。

【讨论】:

    【解决方案2】:

    我会试一试,但我希望v1 == v2 的内部结构会变成这样:

     for(int i = 0; i < v1.size && i < v2.size; i++)
     {
        if (v1[i] != v2[i])
           return false;
     }
    

    [上面可能不是它的实际实现方式,而是显示为“它像这样工作”]

    因此,如果索引 0 是最常见的不同元素,您只会勉强有所收获。

    无论如何,尝试一下(无论如何,这可能比在这里询问要快!)

    当然,就 cmets 而言,这个特定问题的主要部分是“不要在关闭优化的情况下对代码进行基准测试/分析”。当测量微小的细节和紧密的循环代码时,很容易获得 10 倍的性能下降,然后优化被关闭 [如果“调试模式”还启用额外的检查和此类事情以确保没有越界使用,等等,我们可以看到慢 100-1000 倍的代码]

    【讨论】:

    • 我想任何这样的实现都会做的第一件事就是在循环之前比较数组大小:)
    • 是的,我想你是对的——如果我们只是简单地返回“它们是否相等”——通常,结果是“0 表示相等,V1 的正数大于 V2, V1 的负数小于 V2" 或类似的东西,因为它是执行检查的常见“比较”函数。
    • @Mats Petersson:请在您的答案中添加优化提示。谢谢
    【解决方案3】:

    第二个代码块效率稍高一些,但它是不正确的:考虑如果一个或两个向量为空会发生什么。这里唯一的节省来自避免在第一个字符中字符串不同时的调用开销和循环设置开销。这些节省不值得让您的程序复杂化,因为它们太小了。

    如果您希望节省更多资金,请考虑将字符串替换为以不同方式实现相等的自定义类:例如,您可以预先计算并存储向量的哈希码,并使用逐个元素的比较仅当哈希码不同时。

    【讨论】:

      【解决方案4】:

      由于您的类型是基本整数类型,您可以尝试*使用memcmp将它们作为内存块进行比较

      memcpy 获取两个缓冲区 (void*) 并返回 0 如果缓冲区具有相等的内存块

      bool equal = v1.size() == v2.size() && memcmp(&v1.front(), &v2.front(), sizeof(v1[0]) * v1.size()) == 0;
      

      (*) - 我强调了这个词试图表明它没有必要会有所帮助,但这是一种可能性

      【讨论】:

      • 你的意思可能是“memcmp”。
      • 我不相信它的速度会快很多。
      • @MatsPetersson,我想如果它比 1-by-1 更快,它应该在 vector 中使用,但如果它是瓶颈,最好测试一下
      • @mahmood,我添加了一些信息
      • memcmp 仍然进行“逐一”比较,但也许它确实使用了 128 位 SSE 指令,这将所需的指令数量减半。但是考虑到大小是 2-4 个元素,我怀疑它真的有很多收获。
      【解决方案5】:

      我想您的任何实现都将从验证数组大小是否相等开始,然后继续逐个检查元素并比较它们(尽快返回 false - 在第一个差异上)。所以你的建议没有多大帮助,std::mismatch 也没有。

      但是,如果您可以对向量进行排序,也许更智能的检查可能是可行的。可以吗?

      【讨论】:

      • 元素是随机插入的。所以需要额外的排序。
      猜你喜欢
      • 2010-12-25
      • 2023-04-08
      • 1970-01-01
      • 2016-06-29
      • 2016-02-26
      • 1970-01-01
      • 1970-01-01
      • 2022-08-12
      • 1970-01-01
      相关资源
      最近更新 更多