以这种方式使用内联if语句是否有效?

时间:2013-05-30 14:23:12

标签: c#

如果我为一个变量赋值,然后想为它分配第二个值,但只有当它满足条件时,使用速记if语句是否同样有效?这是一个例子。

效率更高

int x = GetInt();
if (x < 5)
    x = 5;

比这个

int x = GetInt();
x = x < 5 ? 5 : x;

我想我真正要问的是,如果x不满足条件,那么else语句中的x = x会影响性能吗?

3 个答案:

答案 0 :(得分:11)

我喜欢这个版本:

int x = Math.Max(5, GetInt());

但请记住,所有这些都是过早的优化。今天更快的速度可能会更快,因为Windows Update会更改框架以添加新的或不同的JIT优化。

我可能会花一些时间查看你是否在一个大循环中运行这样的支票:

 var items = Enumerable.Range(0, 1000000);

 foreach(int item in items)
 {
     if (item % 3 == 0)
     { 
         //...
     }
     else
     {
         //...
     }
 }

检查循环的原因并不多,因为代码将尽可能快地运行很多次,更加强调小的低效率,但是因为你是使用if还是{{1在整个循环中来回变换。

我希望代码效率低下,因为现代cpu的功能称为分支预测。如果elseif的内容非常重要并且差异很大,那么您可以通过移动执行所有这些检查来更快地运行 lot 预测失败)在前端,然后将所有else一起运行,然后运行所有if s。它会更快,因为运行if和else的第二阶段的分支预测(运行起来可能要贵得多)会更准确。

这是一个展示差异的小程序:

else

我的机器上的结果是第二次测试,运行更多,运行得更快:

  

天真未分类的时间:1118652
  分离/分支预测的时间友好:1005190

要带走的重要一点是 not 你需要回过头来看看你的所有循环是否都能从分支预测中受益。这只是可以使性能结果让您大吃一惊的众多CPU功能之一。这里要记住的重要一点是,要确定代码的执行方式,您实际上需要衡量您的表现。如果你没有仔细构建这个天真的技术仍然可以获胜(我的第一次尝试没有达到我预期的速度)。

此外,我需要指出的是,在这些情况下并没有太大的区别。这种表现是否值得,或者你会在其他地方度过更好的时间吗?了解这一点的唯一方法实际上是衡量整个应用的性能,并找出真正花费时间的地方。它在哪里真的比应该的慢?这称为性能分析,并且有一些工具可以帮助您准确地完成此操作。

答案 1 :(得分:3)

此代码

void Main()
{
        int x = GetInt();
        x = x < 5 ?  5 : x;
}

int GetInt()
{return 5;}

以这种方式在IL中翻译

IL_0000:  ldarg.0     
IL_0001:  call        UserQuery.GetInt
IL_0006:  stloc.0     // x
IL_0007:  ldloc.0     // x
IL_0008:  ldc.i4.5    
IL_0009:  blt.s       IL_000E
IL_000B:  ldloc.0     // x
IL_000C:  br.s        IL_000F
IL_000E:  ldc.i4.5    
IL_000F:  stloc.0     // x

GetInt:
IL_0000:  ldc.i4.5    
IL_0001:  ret         

而这一个

void Main()
{
    int x = GetInt();
    if (x < 5) x = 5;
}            

int GetInt()
{return 5;}

被翻译为

IL_0000:  ldarg.0     
IL_0001:  call        UserQuery.GetInt
IL_0006:  stloc.0     // x
IL_0007:  ldloc.0     // x
IL_0008:  ldc.i4.5    
IL_0009:  bge.s       IL_000D
IL_000B:  ldc.i4.5    
IL_000C:  stloc.0     // x

GetInt:
IL_0000:  ldc.i4.5    
IL_0001:  ret         

所以这似乎更“有效”(?)。

但这实际上是一个微观优化,永远不会对你的代码产生任何影响,因此,我建议使用最具可读性的(并且在我看来这与最后一个相符)

修改 肯定Joel Coehoorn的答案是最好的答案:(至少在可读性和代码大小方面)

IL_0000:  ldc.i4.5    
IL_0001:  ldarg.0     
IL_0002:  call        UserQuery.GetInt
IL_0007:  call        System.Math.Max

GetInt:
IL_0000:  ldc.i4.5    
IL_0001:  ret     

答案 2 :(得分:2)

如果x与getter / setter没有关联,编译器应该以x = x的形式踢出任何语句。因此,任何其他事情也会消失。