使用短路评估的好处

10
boolean a = false, b = true;
if ( a && b ) { ... };
大多数编程语言中,由于a为false,所以b不会被计算,因此a && b不可能为真。我的问题是,短路是否从体系结构角度来看更慢?在流水线中,您只需等待结果以确定是否应评估b,还是最好使用嵌套的if语句?这有帮助吗?
此外,有人知道短路求值通常称为什么吗?我之所以问这个问题,是因为我发现我的编程朋友从未听说过短路求值,并表示它并不常见,也没有出现在许多语言中,并且在流水线中效率低下。我对最后一个问题不确定,所以向大家请教!
好的,我想用一个不同的例子来解释一下我的朋友可能的观点。他认为,由于在以下语句中同时计算:
```python result = (condition_a() and condition_b()) or condition_c() ```
必须先计算条件a和b,然后才能计算条件c。而如果使用嵌套的if语句,则可以在满足条件时立即计算条件c,并跳过其他条件的计算。这样做是否更快?
(a) if ( ( a != null ) && ( a.equals(b) ) ) { ... }

如果存在会导致系统崩溃的代码,那么没有短路计算的架构(因此不允许上述语句)将更快地处理这些语句:

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

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

我不知道这是否正确。

谢谢

15个回答

13

短路求值在汇编语言中和if语句一样转换成分支语句(分支语句基本上就是goto),这意味着它的速度不会比if语句慢。

分支通常不会阻塞流水线,但处理器会猜测分支是否被执行,如果处理器的猜测错误,则必须从流水线中清除自猜测错误以来发生的所有操作。

短路求值也是最常见的名称,在大多数语言中以某种形式存在。


11

短路布尔表达式与一些嵌套ifs完全等效,因此与那种方式一样高效。

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

如果b具有CPU架构在分支预测失败时无法取消的副作用,则可能需要延迟,如果两侧始终评估,则不会出现这种延迟。因此,如果您确实发现短路运算符在代码中创建性能瓶颈,则值得关注,但如果没有原因可担忧。

但是,短路运算符的使用与控制流程一样重要,因为可以节省不必要的工作。例如,我使用的语言Perl中常见的习惯用法:

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

Shell语言的惯用法:

do_something || echo "that failed"

或者用C/C++/Java等语言习惯写法:

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

在所有这些情况下,您需要使用短路运算,以便仅在左侧操作数指示必须执行右侧操作数时才对其进行评估。在这种情况下,与错误的替代代码比较性能是没有意义的!


9

我真的不用担心这个。测试布尔值非常快。短路只有在第二个表达式具有副作用时才变得有趣/有用:

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

…或者依赖于第一个测试:

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

6

支持短路求值的编程语言:

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

引自短路求值


3
首先,你的朋友是错误的。在大多数语言中,短路评估(又称最小化评估)都是可用的,并且比嵌套if语句更适用于并行语言(在这种情况下,返回的第一个条件将导致执行继续)。
无论如何,在直接非并行语言中,我不认为嵌套if语句会更快,因为执行会阻塞,直到第一个条件被评估。

3

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在表达您想要实现的行为方面非常详细。


除了做陈述与否定之外,我更想看到的是: 如果 MyObj 不是空且 MyObj.Value 小于 SomeValue。 - Nescio
是的,我想我只是脑海中一直在想OrElse,因为我刚刚使用完它。我已经修复了我的示例。 - Kibbee
今天学到了新东西。我不知道VB有这个问题,但我很确定QBASIC有惰性求值。 - mikek3332002

2

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

问题中的例子相当简单,实际上并没有提供太多性能上的好处。性能好处出现在要求复杂的表达式进行求值时。

举个例子,想象一个游戏程序有类似以下代码:

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

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

我只是想为那些不知道短路的人提供一个例子。当他不知道这就是所谓的短路时,我感到非常惊讶。 - Swati

2

如何使嵌套if不阻塞?实际上,如果a和b都是变量而不是带有副作用的表达式,它们可以被一个好的编译器并行加载。使用更多的if没有任何好处,只会增加您的代码行数。实际上,这将是最糟糕的一种对编译器进行二次猜测的方式。

这被称为短路评估。


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

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

在我看来,这段代码非常易读且功能良好。通常情况下,我会尽量避免过多的嵌套,因为它会导致代码难看。

以上纯属个人意见。


1
是的,那也是我的观点。然而,他说他不喜欢“非常长的if语句”,宁愿嵌套ifs。谢谢! - Swati

2

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


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接