【问题标题】:Performance impact of using 'break' inside 'for-loop'在“for-loop”中使用“break”对性能的影响
【发布时间】:2017-02-15 07:11:28
【问题描述】:

我已尽我所能,阅读了很多关于 SO.SE 的问答,但我还没有找到我的特定问题的答案。大多数for-loopbreak 相关问题都涉及嵌套循环,而我关心的是性能。

我想知道在for-loop 中使用break 是否会影响我的C++ 代码的性能(假设几乎从未调用过中断)。如果有的话,我也想试探一下这个惩罚有多大。

我很怀疑它确实会影响性能(虽然我不知道有多少)。所以我想问你。我的推理如下:

独立于条件语句的额外代码 触发break(如if),它必然会附加广告 对我的循环的说明。

此外,当我的编译器尝试 展开for-loop,因为它不再知道迭代次数 它将在编译时运行,有效地将其呈现为 while-loop.

因此,我怀疑它确实会对性能产生影响,这可能是 对于非常快速和紧凑的循环来说相当可观。


所以这让我想到了一个后续问题。 for-loop & break 在性能方面是否等于 while-loop?就像在下面的 sn-p 中一样,我们假设 checkCondition() 在 99.9% 的时间里计算为 true。我会失去for-loop 的性能优势吗?

// USING WHILE
int i = 100;
while( i-- && checkCondition())
{
    // do stuff
}


// USING FOR
for(int i=100; i; --i)
{
    if(checkCondition()) {
        // do stuff
    } else {
        break;
    }
}

我已经在我的电脑上试过了,但我得到了相同的执行时间。并且对编译器及其优化巫术保持警惕,我想知道概念上的答案。


编辑:

请注意,我在完整代码中测量了两个版本的执行时间,没有任何实际差异。另外,我不相信用-s(我通常这样做)编译这个问题,因为我对我的编译器的特定结果不感兴趣。我对这个概念本身(在学术意义上)很感兴趣,因为我不确定我是否完全正确:)

【问题讨论】:

  • 不,差异是 0。尤其是优化编译器。不要试图微优化你的代码,让你的编译器为你做。
  • 这些循环实际上并不等价。
  • @andresgongora 是的,它们仍然不等价。
  • 关于展开:我看不出编译器为什么不能用 break 展开循环的任何原因,它只会包含几次测试。关于执行 break 本身的惩罚:几乎为零。关于具有中断性能的循环:您也可以从其他角度来看。如果没有中断,您将处理整个循环,而使用中断有时您可能会很早就退出,因此在这种情况下,中断实际上会大大提高性能。如果你能以优雅的方式编写算法的无分支变体,当然可以这样做,但在许多情况下,带有分支的精益优雅算法仍然是最好的。
  • @andresgongora 有研究表明“直觉”在优化方面通常是非常错误的(当您在该领域没有大量实践时)最好总是进行衡量。您还可以检查生成的汇编代码以了解发生了什么。但是不要相信你的直觉。有时你会让事情变得更糟。

标签: c++ performance for-loop while-loop


【解决方案1】:

主要的答案是避免在类似的微优化上花费时间,直到您确认此类条件评估是一个瓶颈。

真正的答案是 CPU 具有强大的分支预测电路,从经验上来说效果非常好。

将会发生的是,您的 CPU 将选择是否采用分支并执行代码,就好像 if 条件甚至不存在一样。当然,这依赖于多个假设,例如对条件计算没有副作用(因此主体循环的一部分依赖于它),并且该条件将始终评估为假,直到它变为真的某个点,并且停止循环。

一些编译器还允许您指定评估的可能性作为分支预测器的提示。

如果您想查看两个代码版本之间的语义差异,只需使用 -S 编译它们并检查生成的 asm 代码,没有其他神奇的方法可以做到这一点。

【讨论】:

  • 那么,循环内部的中断确实对性能有影响吗?
  • 您可以稍微阅读一下这个非常投票的答案:stackoverflow.com/a/11227902/5520058 通过阅读此内容,您会更好地理解@Jack 的答案。
  • @mtb 谢谢。可能我没听懂杰克的回答。
  • 不,我是认真的。这是对 SO 投票最多的问题的投票最多的答案。这是关于分支预测能力的。
【解决方案2】:

对于“...的性能影响是什么”,唯一明智的答案是“衡量它”。通用答案很少。

在您展示的特定情况下,如果优化编译器为两个示例生成显着不同的代码,那将是相当令人惊讶的。另一方面,我可以相信这样的循环:

unsigned sum = 0;
unsigned stop = -1;
for (int i = 0; i<32; i++)
{
    stop &= checkcondition();  // returns 0 or all-bits-set;
    sum += (stop & x[i]);
}

可能比:

unsigned sum = 0;
for (int i = 0; i<32; i++)
{
    if (!checkcondition())
        break;
    sum += x[i];
}

针对特定编译器、针对特定平台、设置了正确的优化级别以及针对特定模式的“检查条件”结果。

...但唯一的判断方法是测量。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2010-09-11
    • 1970-01-01
    • 2012-12-10
    • 1970-01-01
    • 2020-11-04
    • 2013-08-30
    • 2021-03-09
    • 2011-06-08
    相关资源
    最近更新 更多