0

诠释 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 确实会检查第二个和第三个条件。这是真的?

4

5 回答 5

3

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

例如:

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

如果没有else,此代码意味着:

  • s如果是,则执行第一个块null
  • 然后,如果该块更改s""(或s开始""),则执行第二个块。

else在 second 之前有一个额外的if,代码意味着:

  • s如果是 则执行第一个块null
  • s如果不是null以 开头等于 ,则执行第二个块""

如果由于块不会修改您要比较的变量而没有区别,请使用它,else因为它使您的代码的含义明确。

于 2012-12-02T09:18:30.673 回答
2

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

但是你不应该担心它,你的例子中的性能差异是如此之小以至于微不足道。

于 2012-12-02T08:58:03.490 回答
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(s)一样。

编辑 1

在方法中m2()

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

那么方法'm2()'更快。

于 2012-12-02T09:05:05.530 回答
0

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

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

或者

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

在第二种情况下,如果 predicateA 为真,则不需要计算 predicateB(以及任何其他谓词)(因此整个代码将执行得更快),而在第一个示例中,如果 predicateA 为真,则仍将始终计算 predicateB,如果 predicateA 和 predicateB 不是互斥的,你也可能会得到一些意想不到的惊喜。

于 2012-12-02T09:01:49.937 回答
0

如果“DoX”是像“a = b”这样的语句;那么第一个执行速度可能会更快,并且编译器仍然可能无法找出互斥比较的最佳选项。

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

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

如果这些是非常简单的语句,程序员会有所帮助。

转换问题以获得更好性能的其他一些实用方法是使用函数指针并确保每一步都不会访问超出范围的数组。

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

 do[i]();  
 // mov eax, do[eax*4];
 // call [eax]
于 2012-12-02T10:32:31.153 回答