避免在 C++ 循环中的每一步都检查相同的条件

Posted

技术标签:

【中文标题】避免在 C++ 循环中的每一步都检查相同的条件【英文标题】:Avoid checking the same condition every step in a loop in C++ 【发布时间】:2019-11-06 15:13:08 【问题描述】:

我正在检查循环内的一个条件,如果它成立,就做点什么。

for (i = 0; i < n; i++)

    // do lots of work here
    .
    .
    .
    if (constant_condition)
        do_something(n);

条件独立于n,所以每次都检查一下感觉是多余的。我可以这样做:

if (constant_condition)
    for (i = 0; i < n; i++)
    
        // do lots of work here
        .
        .
        .

        do_something(n);
    
else
    for (i = 0; i < n; i++)
    
        // do lots of work here
        .
        .
        .    
    

这个新代码效率更高,但我不得不在我的程序中复制粘贴相同的代码。有没有不重复相同代码块的有效方法?

编辑:条件在编译时未知,但会在运行时给出,不会改变。

【问题讨论】:

只保留条件。如果它很复杂(不仅仅是测试变量),请将条件存储到循环前的bool 变量中。分支预测将消除条件的大部分(如果不是全部)开销。不要重复自己(“干”)。 // do lots of work here做一个函数,然后你就不用重复了。 当你说你有一个constant_condition 时,你说的是在编译时已知的东西,还是在运行时不会改变的东西?也就是说,如果条件永远不会改变,分支预测器将很快学会这一点,并且不会真正花费您任何费用。 为什么大家都投反对票?只是想学习如何编写干净的代码。如果您有改进问题的建议,请告诉我。 如何最好地写这个主要是基于意见。如果您担心性能,那么您最好停止担心并改为编写可读性并测量正在运行的代码而不是事先推测。话虽这么说,在循环之前放一个const bool constant_condition = ...,然后在循环内使用它 【参考方案1】:

首先,配置文件以查看是否重要。如果是这样,您有多种选择:

如果编译器还没有在循环外缓存常量。这是最简单的,在大多数情况下就足够了:

const bool constant_condition = ...;
for (...) 
   ...
   if (constant_condition) do_something(...);

如果你真的需要避免分支,一个典型的方法是定义一个辅助函数或一个本地 lambda (C++11) 来分解出常见的代码块。但是,这仍然会重复代码,并且根据具体情况,可能看起来一点也不漂亮:

auto main_work = [...](...)  ... ;
if (constant_condition)
    for (...)  main_work(...); 
else
    for (...)  main_work(...); do_something(...); 

定义模板并根据需要进行参数化。编译器通常会正确优化,因此您可以简单地复制粘贴代码。如果你真的想确保删除分支,你可以强制它专门化模板,或者利用if constexpr (C++17) 等。但是,要注意代码膨胀和编译时间。

template <bool constant_condition>
void f(...)  ... 

if (constant_condition)
    f<true>(...);
else
    f<false>(...);

最后,不要忘记再次配置文件。有时,删除一个分支可能看起来不错,但总体上是有害的。如果代码发生很大变化并且最初看起来像一个小的重复指令现在是几个充满重复代码的内存页面,则尤其如此。

另一种选择是尝试查看算法/代码是否可以改为无分支;但是,这不是一个通用的解决方案。

【讨论】:

个人资料确实如此,但这不是问题的答案。说出来没有区别。那么OP就不知道为什么了【参考方案2】:

我没有分析这段代码,但由于 CPU 中的分支预测器,这肯定会对代码速度产生微不足道的影响。

if 指令会通过 CPU 一堆,但是在涉及到分支时,对代码速度的主要影响是并行化、乱序指令执行和缓存优化被搞砸了,但它们不会受到干扰,因为分支预测器。

【讨论】:

以上是关于避免在 C++ 循环中的每一步都检查相同的条件的主要内容,如果未能解决你的问题,请参考以下文章

第二章 算法

第二章 算法

在需要计数器时避免 SQL 中的 while 循环

每一步都是积蓄未来

在使用非 Equi 连接条件时避免使用嵌套循环连接

如何制作react组件包上传到npm