【问题标题】:Reducing for loop overhead减少 for 循环开销
【发布时间】:2011-07-22 20:47:34
【问题描述】:

我需要遍历一个摊销公式,如下所示:

R = ( L * (r / m) ) / ( 1 - pow( (1 + (r / m)), (-1 * m * t ) );

我使用for 循环进行迭代,每次将 L(贷款价值)增加 1。循环工作得很好,但它确实让我想知道别的东西,这是在循环执行之前执行基本操作然后通过变量引用这些值的值(或缺少值)。例如,我可以进一步修改这个函数看起来像

// outside for loop
amortization = (r/m)/(1 - pow( (1+(r/m)), (-1*m*t) ) )

// inside for loop
R = L * amortization

这样,我不必在循环的每次迭代中执行大量数学运算,只需引用变量数量并执行单个运算。

我想知道这有多相关?提取这些操作是否有任何实际价值,或者节省的时间是如此之少,以至于我们正在谈论从迭代大约的 for 循环中节省毫秒的时间。 200,000 次。后续问题:如果我进行像 sqrt 这样更昂贵的操作,那么提取这样的操作是否值得?

(注意:如果这很重要,我在问这个问题时特别考虑了 c++)

【问题讨论】:

  • 编译器无论如何都会做这种事情 - 试试谷歌的“循环不变”。
  • 为什么不自己看看有什么不同呢?我认为实验可能比问这个问题要快。
  • @Rooke 我确实尝试过,但没有看到性能差异。显然这是由于“循环不变代码”。

标签: c++ performance iteration


【解决方案1】:

编译器会在这里使用一种称为循环不变代码运动的优化技术。它几乎可以完成您手动执行的操作,即将在循环中重复评估的表达式的常量部分提取到存储在变量(或寄存器)中的预先计算的值中。因此,您自己执行此操作不太可能获得任何性能。

当然,如果速度很关键,您应该分析和/或检查编译器在这两种情况下生成的汇编代码。

【讨论】:

    【解决方案2】:

    编译器已经将循环不变代码移到循环外部。这种优化称为“Loop Invariant Code Motion”或“提升不变量”。

    如果您想知道它对性能的影响有多大,那么您要知道的唯一方法就是尝试一下。我想如果你这样做 200,000 次,那么它肯定会影响性能(如果编译器还没有为你这样做)。

    【讨论】:

      【解决方案3】:

      正如其他人所提到的,好的编译器会自动进行这种优化。不过……

      首先,pow 可能是一个库函数,所以你的编译器可能知道也可能不知道它是一个“纯”函数(即它的行为仅取决于它的参数)。如果没有,它将无法执行此优化,因为它知道pow 可能会打印一条消息或其他内容。

      其次,无论如何,我认为将这个表达式排除在循环之外会使代码更容易理解。阅读您的代码的人也可以“自动”分解出这个表达式,但为什么要制作它们呢?它只会分散他们对算法流程的注意力。

      所以我会说无论如何都要进行此更改。

      也就是说,如果您真的关心性能,请获得一个不错的分析器,并且在它告诉您之前不要担心微优化。您早期的优先事项应该是 (a) 使用体面的算法和 (b) 清楚地实施它。而且不是这个顺序。

      【讨论】:

      • 虽然我对节省速度感到好奇,但实际上更多的是从教育的角度来看。如题,编译器查看和执行代码的方式会有什么区别,区别会很明显吗?
      • @Moses: 一个好的优化编译器可以证明pow 是一个纯函数并且rmt 在循环中是常量,将生成完全相同的代码对彼此而言。但这样的证明可能比你想象的要难。例如,如果r 是一个全局的并且您在循环中调用任何(非内联、非纯)函数,编译器将不知道r 没有改变......所以它无法将表达式从循环中取出。对于复杂的表达式,手动取出它们有时会使代码更快,通常更容易阅读,IMO。
      • 最后一个问题,你知道像 JavaScript 这样的非编译语言是否能够优化不变代码?我做了一些谷歌搜索,但一无所获,但我很确定我记得在某个地方读过他们所做的。
      • 这取决于解释器。大多数“非编译语言”实际上是“即时编译的”,并且“即时”编译器可以执行许多与其他任何相同的优化。例如,如果 Google Chrome 中的 Javascript 解释器做了一些花哨的事情,我不会感到惊讶。但无论如何我还是会自己分解表达式:-)
      • ++ 如果分析显示需要花费大量时间,那么显然将pow 移出循环将赢得大量时间。也就是说,我永远不会把我的衬衫赌在编译器能够自动完成这件事上,如果它对我来说很容易做到的话。
      【解决方案4】:

      当您启用优化时,将常量表达式移出循环是编译器非常擅长自己做的事情,所以这可能不会给您带来任何加速。

      但是,如果这看起来不是一个合理的尝试,那么如果这实际上花费的时间比您要求的要长,那么就计时。

      【讨论】:

        猜你喜欢
        • 2019-12-13
        • 2011-12-22
        • 2011-10-29
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2011-02-06
        • 2017-07-22
        相关资源
        最近更新 更多