使用短路评估的好处

时间:2020-03-06 14:19:37  来源:igfitidea点击:
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)。在这种情况下,允许短路的语言会比不允许短路的语言慢。

我不知道那是不是真的。

谢谢

解决方案

如果没有失速怎么办?实际上,如果a和b都是变量,而不是带有副作用的表达式,则可以由良好的编译器并行加载它们。除了增加行数之外,使用更多ifs没有任何好处。确实,这是第二次猜测编译器是最糟糕的一种。

这称为短路评估。

根据上下文,它也可以称为"防护"。

而且我几乎在我使用过的每种语言中都看到过这种语言,这种语言将近十二种。

如果语句是(分支基本上是goto),则短路评估以相同的方式转换为汇编语言的分支(这意味着分支不会比if语句慢)。

分支通常不会使流水线停滞,但是处理器会猜测是否采用了分支,如果处理器错误,则必须刷新自流水线做出错误猜测以来发生的所有事情。

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

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

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

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

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

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

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

在我看来,这是很容易理解的,并且功能很好。通常,我会尽量避免过多的嵌套,因为它会导致难看的代码。

我所有的意见虽然。

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

问题中的示例是一个非常简单的示例,实际上并没有提供太多的性能优势。当表达式要计算复杂时,可以带来性能优势。

作为一个很好的例子,假设一个游戏程序具有以下内容:

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

在这种情况下,冲突检测比主动检查要昂贵得多。如果系统中有许多不活动的对象,则性能将得到显着提高。

我对流水线一无所知,但是短路评估是许多语言的共同特征(这也是我所知道的名称)。在C中,&&和其他运算符定义序列点,就像;一样。运算符可以,所以我没有看到短路评估比仅使用多个语句效率低多少。

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

无论如何,即使使用一种简单的非并行语言,我也看不到ifs嵌套会如何更快,因为执行会阻塞直到评估第一个条件。

我只听说过短路。在管道中,下一个操作是否不取决于if语句的结果?如果是这种情况,则可以对其进行更优化,从而不必每次都测试两个值。

短路或者最小评估只是嵌套if的语法糖。

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

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

一个线程是顺序线程,因此如果我们有两个if,则第一个线程当然会在第二个线程之前求值,因此我看不出有什么区别。我使用的条件AND运算符(即&&称为afaik)比嵌套的ifs更多。如果我想检查可能需要一段时间才能评估的内容,请先进行简单的测试,然后再进行有条件的和之后的较难的测试。

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

Answer

Regarding whether or not short-circuiting is efficient, pipelining is unlikely to have much of an impact on performance. In situations where it could have an impact, there's nothing to stop the compiler from testing multiple conditions in parallel so long as these tests doesn't have side-effects. Plus, modern CPUs have several mechanisms useful for improving the pipeline performance of branchy code.

Nested ifs will have the same effect as short-circuiting &&.

'Short-circuit evaluation' is the most common name for it, and your friend is wrong about it being uncommon; it's very common.

Answer

VB.Net has a different syntax depending on whether or not you want it to short circuit or not.  Because of legacy reasons, the default behaviour is to not short circuit.  The syntax is as follows

Non Short Circuit

IF A And B THEN
    ...
END IF

似乎没有什么不同

IF A AndAlso B THEN
    ...
END IF

如果要短路OR语句,可以使用Or / OrElse。在以下情况下,这真的很好

就我个人而言,虽然我知道短路可以加快速度,但是从看代码来看,绝对不是显而易见的事情。我可能会看到一个经验不足的开发人员对该行为感到困惑。甚至似乎可能会发生某些事情,取决于优化级别的编译器标志。我喜欢VB如何详细说明我们实际想要完成的行为。

布尔布尔表达式完全等同于一组嵌套的ifs,因此效率会很高。

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

如果b具有分支预测失败时CPU体系结构无法消除的副作用,则是的,这可能需要延迟,而如果总是对双方进行评估,则不会出现延迟。因此,如果我们确实发现短路操作员正在代码中创建性能瓶颈,那值得一看,但不值得担心。

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

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

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

外壳成语:

do_something || echo "that failed"

或者C / C ++ / Java / etc习惯用法:

在所有这些情况下,都需要短路,因此只有在LHS指示应进行RHS评估时,才对RHS进行评估。在这种情况下,将性能与错误的备用代码进行比较是毫无意义的!

支持短路的语言:

Ada,埃菲尔,ALGOL 68,C1,C ++,C#,Java,R,Erlang,标准ML,Javascript,MATLAB,Lisp,Lua,方案,OCaml,Haskell,Pascal,Perl,Ruby,PHP,Python,Smalltalk,Visual Basic 。网

段落数量不匹配

代码数量不匹配