【问题标题】:Benefits of using short-circuit evaluation使用短路评估的好处
【发布时间】:2010-09-10 11:44:53
【问题描述】:
boolean a = false, b = true;
if ( a && b ) { ... };

在大多数语言中,b 不会被评估,因为a 为假,所以a && b 不能为真。我的问题是,就架构而言,短路不会更慢吗?在管道中,您是否只是在等待获得 a 的结果以确定是否应评估 b 时停止?做嵌套ifs会更好吗?这有帮助吗?

另外,有谁知道短路评估通常被称为什么?这个问题是在我发现我的编程朋友从未听说过短路评估并表示它不常见,在许多语言中都没有,并且在管道中效率低下之后出现的。我不确定最后一个,所以问你们!

好的,我想一个不同的例子来解释我的朋友可能来自哪里。他认为,由于并行评估如下语句:

(a) if ( ( a != null ) && ( a.equals(b) ) ) { ... }

会使系统崩溃,没有短路(因此不允许上述语句)的架构在处理这样的语句时会更快:

(b) if ( ( a == 4 ) && ( b == 5 ) )

因为如果它不能并行执行 (a),它就不能并行执行 (b)。在这种情况下,允许短路的语言比不允许短路的语言慢。

不知道是真是假。

谢谢

【问题讨论】:

    标签: architecture pipeline


    【解决方案1】:

    短路求值被翻译成汇编语言中的分支,方式与 if 语句相同(分支基本上是 goto),这意味着它不会比 if 语句慢。

    分支通常不会停止流水线,但处理器会猜测分支是否被采用,如果处理器错误,它将不得不刷新所有发生的事情,因为它从流水线中做出了错误的猜测。

    短路评估也是它最常见的名称,在大多数语言中都以某种形式出现。

    【讨论】:

      【解决方案2】:

      短路布尔表达式完全等价于一些嵌套的 if 集合,因此与它一样高效。

      如果 b 没有副作用,它仍然可以与 a 并行执行(对于“并行”的任何值,包括流水线)。

      如果 b 具有在分支预测失败时 CPU 架构无法取消的副作用,那么是的,这可能需要延迟,如果始终评估双方,则不会存在延迟。因此,如果您发现短路运算符会在您的代码中造成性能瓶颈,则值得关注,否则不值得担心。

      但是短路用于控制流,以节省不必要的工作。这在我使用过的语言中很常见,例如 Perl 成语:

      open($filename) or die("couldn't open file");
      

      shell 成语:

      do_something || echo "that failed"
      

      或 C/C++/Java/etc 成语:

      if ((obj != 0) && (obj->ready)) { do_something; } // not -> in Java of course.
      

      在所有这些情况下,您都需要短路,以便仅在 LHS 规定应该进行时才评估 RHS。在这种情况下,将性能与错误的替代代码进行比较是没有意义的!

      【讨论】:

        【解决方案3】:

        老实说,我不会担心。测试布尔值真的很快。只有当第二个表达式有副作用时,短路才会变得有趣/有用:

        if ( ConfirmAction() && DestroyAllData() )
           Reboot();
        

        ...或者取决于第一个测试:

        if ( myDodgyVar != null && myDodgyVar.IsActive() )
           DoSomethingWith(myDodgyVar);
        

        【讨论】:

          【解决方案4】:

          支持短路的语言:

          Ada、Eiffel、ALGOL 68、C1、C++、C#、Java、R、Erlang、标准 ML、Javascript、MATLAB、Lisp、Lua、Scheme、OCaml、Haskell、Pascal、Perl、Ruby、PHP、Python、Smalltalk , Visual Basic .NET

          取自Short-circuit evaluation

          【讨论】:

            【解决方案5】:

            VB.Net 有不同的语法,具体取决于您是否希望它短路。由于遗留原因,默认行为是不短路。语法如下

            非短路

            IF A And B THEN
                ...
            END IF
            

            短路

            IF A AndAlso B THEN
                ...
            END IF
            

            如果你想短路 OR 语句,你可以使用 Or / OrElse。这在以下情况下非常好

            If MyObj IsNot Nothing AndAlso MyObj.Value < SomeValue Then
                ....
            End If
            

            就我个人而言,虽然我知道短路可以加快速度,但这绝对不是仅仅看代码就能明显看出的。我可以看到一个没有经验的开发人员对这种行为感到困惑。根据优化级别的编译器标志,它甚至看起来可能会发生或不会发生。我喜欢 VB 对您实际想要完成的行为的详细说明。

            【讨论】:

            • Modus ponens / tollens 旁边,我更愿意看到:If MyObj IsNot Nothing AndAlso MyObj.Value
            • 是的,我想我刚用完 OrElse 就想到了它。我已经修复了我的示例。
            • 今天学到了一些新东西。不知道VB有这个问题,我很确定QBASIC有惰性评估。
            【解决方案6】:

            首先,你的朋友错了。短路评估(又名最小评估)在大多数语言中都可用,并且比并行语言的嵌套 if 更好(在这种情况下,返回的第一个条件将导致执行继续)

            在任何情况下,即使在简单的非并行语言中,我也看不到嵌套 if 会更快,因为在评估第一个条件之前执行会阻塞。

            【讨论】:

              【解决方案7】:

              嵌套如果不停止怎么办?实际上,如果 a 和 b 都是变量而不是具有副作用的表达式,它们可以由一个好的编译器并行加载。除了增加行数之外,使用更多 if 没有任何好处。真的,这将是最糟糕的第二次猜测编译器。

              这称为短路评估。

              【讨论】:

                【解决方案8】:

                我使用的一个有用的短路是这样的:

                if (a != null && a.equals(somevalue)) {
                    ... do something.
                }
                

                在我看来,这是非常易读的,并且功能非常好。一般来说,我尽量避免过多的嵌套,因为它会导致代码丑陋。

                不过都是我的意见。

                【讨论】:

                • 是的,这也是我的看法。但是,他表示他不喜欢“非常长的 if 语句”,而宁愿嵌套 if。谢谢!
                【解决方案9】:

                大多数语言都会对布尔表达式进行短路计算。我一直听说它被称为短路评估。

                问题中的示例是一个非常简单的示例,并没有真正提供太多性能优势。当表达式计算复杂时,性能优势就会出现。

                作为一个很好的例子,想象一个游戏程序有这样的东西:

                if (someObject.isActive() && someOtherObject.isActive() && CollisionDetection.collides(someObject, someOtherObject) {
                  doSomething();
                }
                

                在这种情况下,碰撞检测比主动检查要昂贵得多。如果系统中有很多不活动的对象,将会有显着的性能提升。

                【讨论】:

                • 我只是想为其他生活在岩石下并且没有听说过短路的人举一个例子。当他不知道它叫什么时,我非常感到惊讶。
                【解决方案10】:

                短路或最小求值只是嵌套 if 的语法糖。 假设它效率低下或导致停顿是过早优化的情况。 在这一点上,大多数编译器都足够智能,可以正确解释和优化这些语句。使用这些语句可以大大减少嵌套,从而提高代码的可读性,这应该是您的首要目标。

                【讨论】:

                  【解决方案11】:

                  关于短路是否有效,流水线不太可能对性能产生太大影响。在可能产生影响的情况下,只要这些测试没有副作用,就没有什么可以阻止编译器并行测试多个条件。此外,现代 CPU 有多种机制可用于提高分支代码的流水线性能。

                  嵌套 if 将与短路 && 具有相同的效果。

                  “短路评估”是它最常见的名称,您的朋友认为它不常见是错误的;这很常见。

                  【讨论】:

                    【解决方案12】:

                    我对流水线一无所知,但短路评估是许多语言的共同特征(这也是我知道它的名称)。在 C 中,&& 和其他运算符定义 sequence point 就像 ;运算符确实如此,所以我看不出短路评估比仅使用多个语句效率低多少。

                    【讨论】:

                      【解决方案13】:

                      我只听说它是短路。在管道中,下一个操作是否取决于 if 语句的结果?如果是这种情况,这将更加优化,因此它不必每次都测试两个值。

                      【讨论】:

                        【解决方案14】:

                        单个线程是顺序的,所以如果你有两个 if,当然第一个会在第二个之前被评估,所以我看不出有什么区别。我使用条件与运算符(这就是 && 被称为 afaik)比嵌套 if 更多。如果我想检查可能需要一段时间才能评估的东西,我会先做简单的测试,然后在条件 and 之后做更难的测试。

                        a = obj.somethingQuickToTest() &amp;&amp; obj.somethingSlowToTest();

                        好像没有什么不同

                        a = false;
                        if(obj.somethingQuickToTest())
                           a = obj.somethingSlowToTest();

                        【讨论】:

                          【解决方案15】:

                          根据上下文,它也可以称为“守卫”。

                          而且我几乎在我工作过的每一种语言中都看到了它——接近十几种。

                          【讨论】:

                          • 懒惰的评估是不同的;当您只在确定知道将使用其结果的时间和地点时才费心评估表达式。
                          猜你喜欢
                          • 2012-05-17
                          • 1970-01-01
                          • 2020-03-29
                          • 2015-11-14
                          • 2017-01-21
                          • 2012-02-10
                          • 2010-12-21
                          • 1970-01-01
                          • 2018-09-01
                          相关资源
                          最近更新 更多