Optional Else会影响性能吗?

时间:2012-12-02 08:55:18

标签: c# if-statement cpu cil

int i = 3;

此代码之间是否存在任何性能差异:

if(i == 2)
   DoA();
if(i == 3)
   DoB();
if(i == 4)
   DoC();

这段代码:

if(i == 2)
   DoA();
else if(i == 3)
   DoB();
else if(i == 4)
   DoC();

我想知道使用可选的ELSE是否会影响CPU如何理解代码。我总是认为当我们使用第二种方法时,如果i2,那么CPU不检查其他两个条件,但是在第一种方法中,尽管第一种条件为真(i == 2 )但CPU会检查第二和第三个条件。这是真的吗?

5 个答案:

答案 0 :(得分:3)

您不应该根据表现来决定这一点。 代码的两个版本意味着不同的东西。您应该使用正确的那个。

例如:

if (s == null)
{
    // do something
    s = GetNewValue();
}
if (s == "")
{
    // do something else
}

没有else,此代码表示:

  • 如果snull
  • ,请执行第一个阻止
  • 然后,如果该块已将s更改为""(或s开始为""),请执行第二个块。

在第二个else之前额外if,代码表示:

  • 如果snull,则执行第一个阻止。
  • 如果s不是null,则执行第二个阻止等于""

如果没有区别因为块不会修改您要比较的变量,使用else因为它会使您的代码明确显示。

答案 1 :(得分:2)

当然它确实会影响 - 为了更好!这完全与不必要的相反,因为通过使用这些elses,编译器将跳过其他if-checks并获得更好的性能。

但你不应该担心它,你的例子中的表现差异是如此之小,以至于无关紧要。

答案 2 :(得分:1)

以下是您的两个陈述的IL代码:

.method private hidebysig static void m1() cil managed
{
    .maxstack 2
    .locals init (
        [0] int32 i,
        [1] bool CS$4$0000)
    L_0000: nop 
    L_0001: ldc.i4.3 
    L_0002: stloc.0 
    L_0003: ldloc.0 
    L_0004: ldc.i4.2 
    L_0005: ceq 
    L_0007: ldc.i4.0 
    L_0008: ceq 
    L_000a: stloc.1 
    L_000b: ldloc.1 
    L_000c: brtrue.s L_0014
    L_000e: call void ConsoleApplication1.Program::DoA()
    L_0013: nop 
    L_0014: ldloc.0 
    L_0015: ldc.i4.3 
    L_0016: ceq 
    L_0018: ldc.i4.0 
    L_0019: ceq 
    L_001b: stloc.1 
    L_001c: ldloc.1 
    L_001d: brtrue.s L_0025
    L_001f: call void ConsoleApplication1.Program::DoB()
    L_0024: nop 
    L_0025: ldloc.0 
    L_0026: ldc.i4.4 
    L_0027: ceq 
    L_0029: ldc.i4.0 
    L_002a: ceq 
    L_002c: stloc.1 
    L_002d: ldloc.1 
    L_002e: brtrue.s L_0036
    L_0030: call void ConsoleApplication1.Program::DoC()
    L_0035: nop 
    L_0036: ret 
}

.method private hidebysig static void m2() cil managed
{
    .maxstack 2
    .locals init (
        [0] int32 i,
        [1] bool CS$4$0000)
    L_0000: nop 
    L_0001: ldc.i4.3 
    L_0002: stloc.0 
    L_0003: ldloc.0 
    L_0004: ldc.i4.2 
    L_0005: ceq 
    L_0007: ldc.i4.0 
    L_0008: ceq 
    L_000a: stloc.1 
    L_000b: ldloc.1 
    L_000c: brtrue.s L_0016
    L_000e: call void ConsoleApplication1.Program::DoA()
    L_0013: nop 
    L_0014: br.s L_003a
    L_0016: ldloc.0 
    L_0017: ldc.i4.3 
    L_0018: ceq 
    L_001a: ldc.i4.0 
    L_001b: ceq 
    L_001d: stloc.1 
    L_001e: ldloc.1 
    L_001f: brtrue.s L_0029
    L_0021: call void ConsoleApplication1.Program::DoB()
    L_0026: nop 
    L_0027: br.s L_003a
    L_0029: ldloc.0 
    L_002a: ldc.i4.4 
    L_002b: ceq 
    L_002d: ldc.i4.0 
    L_002e: ceq 
    L_0030: stloc.1 
    L_0031: ldloc.1 
    L_0032: brtrue.s L_003a
    L_0034: call void ConsoleApplication1.Program::DoC()
    L_0039: nop 
    L_003a: ret 
}

看起来生成的IL NOT 相同。

编辑1

方法m2()

L_0014: br.s L_003a
.
.
.
L_0027: br.s L_003a

然后方法'm2()'更快。

答案 3 :(得分:0)

是的,请使用else if,请考虑以下代码:

if(predicateA){
  //do Stuff
}
if(predicateB){
  // do more stuff
}

if(predicateA){
  //do stuff 
}
else if(predicateB){
  //do stuff
}

在第二种情况下,如果predicateA为true,则不需要评估predicateB(以及任何进一步的谓词)(因此整个代码将执行得更快),而在第一个示例中,如果predicateA为true,则predicateB仍将始终如果谓词A和谓词B不相互排斥,你可能会得到一些意想不到的惊喜。

答案 4 :(得分:0)

如果'DoX'是'a = b'之类的陈述;那么第一个执行速度可能会更快,编译器仍然无法找到互斥比较的最佳选择。

在某些架构中,这三种比较可以转换为:

 cmp a,2;
 movlt  b, c;
 moveq  c, d;
 movgt  e, f;

Iff 这些都是非常简单的陈述,而程序员也有所帮助。

转换问题以获得更好性能的一些其他实用方法是使用函数指针并尽一切步骤来保证,不可能访问超出范围的数组。

 void (*do)()[]={ doA, doB, doC };

 do[i]();  
 // mov eax, do[eax*4];
 // call [eax]