C# 其他选项是否会影响性能?
int i=3 此代码之间是否存在性能差异: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不会检查其他两个条件,但是在第一种方法中,尽管第一个条
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谢谢你,我只是好奇,我永远不会更改代码,只是想知道黑盒中发生了什么。更重要的是,在你告诉我们的几秒钟内