10
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)。在这种情况下,允许短路的语言比不允许短路的语言慢。

我不知道这是不是真的。

谢谢

4

15 回答 15

12

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

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

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

于 2008-09-18T01:24:48.553 回答
10

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

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

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

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

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

贝壳成语:

do_something || echo "that failed"

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

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

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

于 2008-09-18T01:55:13.143 回答
8

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

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

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

if ( myDodgyVar != null && myDodgyVar.IsActive() )
   DoSomethingWith(myDodgyVar);
于 2008-09-18T01:25:43.543 回答
5

支持短路的语言:

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 。网

取自短路评估

于 2009-06-21T19:00:09.167 回答
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 对您实际想要完成的行为的详细说明。

于 2008-09-18T01:36:56.887 回答
2

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

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

于 2008-09-18T01:27:23.257 回答
1

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

这称为短路评估。

于 2008-09-18T01:23:54.547 回答
1

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

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

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

我的所有意见。

于 2008-09-18T01:25:44.823 回答
1

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

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

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

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

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

于 2008-09-18T01:25:51.030 回答
1

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

于 2008-09-18T01:29:03.143 回答
1

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

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

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

于 2008-09-18T01:34:51.773 回答
0

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

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

于 2008-09-18T01:24:35.230 回答
0

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

于 2008-09-18T01:26:11.373 回答
0

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

于 2008-09-18T01:28:10.230 回答
0

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

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

似乎没有什么不同

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

于 2008-09-18T01:31:10.330 回答