C# 其他选项是否会影响性能?

C# 其他选项是否会影响性能?,c#,if-statement,cpu,cil,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理解代码的方式。我一直认为,当我们使用第二种方法时,如果I是2,那么CPU不会检查其他两个条件,但是在第一种方法中,尽管第一个条

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理解代码的方式。我一直认为,当我们使用第二种方法时,如果
I
2
,那么CPU不会检查其他两个条件,但是在第一种方法中,尽管第一个条件为真(
I==2
),但CPU会检查第二个和第三个条件。这是真的吗?

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

但是您不应该担心,您的示例中的性能差异是如此之小,以至于无关紧要。

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


但是你不应该为此而烦恼,你的例子中的性能差异太小了,这是微不足道的。

是的,使用另一个if,考虑下面的代码:

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


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

是的,使用另一个if,考虑下面的代码:

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


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

以下是您两个语句的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看起来不一样

编辑1

在方法
m2()
中:


然后方法“m2()”会更快。

以下是两条语句的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看起来不一样

编辑1

在方法
m2()
中:


那么方法“m2()”就更快了。

您不应该根据性能来决定这一点这两个版本的代码含义不同。您应该使用正确的版本

例如:

if (s == null)
{
    // do something
    s = GetNewValue();
}
if (s == "")
{
    // do something else
}
如果没有
else
,此代码表示:

  • 如果
    s
    null
  • 然后,如果该块从
    s
    更改为
    (或者
    s
    开始是
    ),则执行第二个块
如果在第二个
if
之前有一个额外的
else
,则该代码表示:

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

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

您不应基于性能来决定这一点这两个版本的代码含义不同。您应该使用正确的版本

例如:

if (s == null)
{
    // do something
    s = GetNewValue();
}
if (s == "")
{
    // do something else
}
如果没有
else
,此代码表示:

  • 如果
    s
    null
  • 然后,如果该块从
    s
    更改为
    (或者
    s
    开始是
    ),则执行第二个块
如果在第二个
if
之前有一个额外的
else
,则该代码表示:

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

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

如果“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]

如果“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]

这是真的。不过,请不要过早地进行优化。做有意义的事情,而不是更快的事情。@Mahdi jan,代码优化可能会为您解决问题,我认为上面的两个代码是相同的。@JanDvorak谢谢你,我只是好奇,我永远不会更改代码,只是想知道黑盒中发生了什么。更重要的是,在你告诉我们的几秒钟内