是条件运算慢? [英] Is the conditional operator slow?

查看:150
本文介绍了是条件运算慢?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我一直在寻找一些code在每个情况下,巨大的switch语句和if-else语句,并立即感到优化的冲动。作为一名优秀的开发人员总是应该做的我开始得到一些硬定时的事实,并开始与三个变种:

I was looking at some code with a huge switch statement and an if-else statement on each case and instantly felt the urge to optimize. As a good developer always should do I set out to get some hard timing facts and started with three variants:


  1. 原来的code是这样的:

  1. The original code looks like this:

public static bool SwitchIfElse(Key inKey, out char key, bool shift)
{
    switch (inKey)
    {
       case Key.A: if (shift) { key = 'A'; } else { key = 'a'; } return true;
       case Key.B: if (shift) { key = 'B'; } else { key = 'b'; } return true;
       case Key.C: if (shift) { key = 'C'; } else { key = 'c'; } return true;
       ...
       case Key.Y: if (shift) { key = 'Y'; } else { key = 'y'; } return true;
       case Key.Z: if (shift) { key = 'Z'; } else { key = 'z'; } return true;
       ...
       //some more cases with special keys...
    }
    key = (char)0;
    return false;
}


  • 第二个变量转换成使用条件运算符:

  • The second variant converted to use the conditional operator:

    public static bool SwitchConditionalOperator(Key inKey, out char key, bool shift)
    {
        switch (inKey)
        {
           case Key.A: key = shift ? 'A' : 'a'; return true;
           case Key.B: key = shift ? 'B' : 'b'; return true;
           case Key.C: key = shift ? 'C' : 'c'; return true;
           ...
           case Key.Y: key = shift ? 'Y' : 'y'; return true;
           case Key.Z: key = shift ? 'Z' : 'z'; return true;
           ...
           //some more cases with special keys...
        }
        key = (char)0;
        return false;
    }
    


  • 使用扭曲字典pre-充满键/字符对:

  • A twist using a dictionary pre-filled with key/character pairs:

    public static bool DictionaryLookup(Key inKey, out char key, bool shift)
    {
        key = '\0';
        if (shift)
            return _upperKeys.TryGetValue(inKey, out key);
        else
            return _lowerKeys.TryGetValue(inKey, out key);
    }
    


  • 请注意:两个switch语句具有完全相同的案件和具有字典字符的等量

    Note: the two switch statements have the exact same cases and the dictionaries have an equal amount of characters.

    我期待:1)和2)是在性能上有些相似,而且3)会稍微慢一些。

    I was expecting that 1) and 2) was somewhat similar in performance and that 3) would be slightly slower.

    对于每一种方法运行两次10.000.000迭代热身,然后定时,让我惊讶,我得到以下结果:

    For each method running two times 10.000.000 iterations for warm-up and then timed, to my amazement I get the following results:


      每次呼叫
    1. 0.0000166毫秒

    2. 每次呼叫
    3. 0.0000779毫秒

    4. 每次呼叫
    5. 0.0000413毫秒

    怎么能这样呢?条件运算符比if-else语句慢四倍,​​比字典查询起坐慢几乎两倍。我缺少的东西必不可少这里还是有条件的经营者天生就慢?

    How can this be? The conditional operator is four times slower than if-else statements and almost two times slower than dictionary look-ups. Am I missing something essential here or is the conditional operator inherently slow?

    更新1:的几个有关我的测试工具的话。我运行下面的(伪)$ C $一个的发布编译的.Net 3.5在Visual Studio项目在c上述每个变种2010 code优化开启和调试/跟踪常量被关闭。我做一个定时运行前的热身被测运行的方法一次。 run方法执行的方法,进行了大量的迭代,用设置为两个真假,并与选定的一组输入键:

    Update 1: A few words about my test harness. I run the following (pseudo)code for each of the above variants under a Release compiled .Net 3.5 project in Visual Studio 2010. Code optimization is turned on and DEBUG/TRACE constants are turned off. I run the method under measurement once for warm-up before doing a timed run. The run method executed the method for a large number of iterations, with shift set to both true and false and with a select set of input keys:

    Run(method);
    var stopwatch = Stopwatch.StartNew();
    Run(method);
    stopwatch.Stop();
    var measure = stopwatch.ElapsedMilliseconds / iterations;
    

    Run方法是这样的:

    The Run method looks like this:

    for (int i = 0; i < iterations / 4; i++)
    {
        method(Key.Space, key, true);
        method(Key.A, key, true);
        method(Key.Space, key, false);
        method(Key.A, key, false);
    }
    

    更新2:挖进一步,我已经看过了IL 1产生的)和2),发现主开关的结构是相同的,因为我所期望的,但这样的身体有轻微的差别。下面是我在看的IL:

    Update 2: Digging further, I have looked at the IL generated for 1) and 2) and find that the main switch structures are identical as I would expect, yet the case bodies have slight differences. Here is the IL I'm looking at:

    1)if / else语句:

    1) If/else statement:

    L_0167: ldarg.2 
    L_0168: brfalse.s L_0170
    
    L_016a: ldarg.1 
    L_016b: ldc.i4.s 0x42
    L_016d: stind.i2 
    L_016e: br.s L_0174
    
    L_0170: ldarg.1 
    L_0171: ldc.i4.s 0x62
    L_0173: stind.i2 
    
    L_0174: ldc.i4.1 
    L_0175: ret 
    

    2)条件运算符:

    2) The Conditional Operator:

    L_0165: ldarg.1 
    L_0166: ldarg.2 
    L_0167: brtrue.s L_016d
    
    L_0169: ldc.i4.s 0x62
    L_016b: br.s L_016f
    
    L_016d: ldc.i4.s 0x42
    L_016f: stind.i2 
    
    L_0170: ldc.i4.1 
    L_0171: ret 
    

    有些意见:


      的if / else分支时是假的,而
    • 条件运算符分支时​​等于true。

    • 虽然1)实际上编译比2几个指令),当是真或假执行的指令数,等于两个。

    • 的指令排序为1)是这样的,只有一个堆栈槽是在所有时间被占用,而2)总是加载两项。

    • The conditional operator branches when shift equals true while if/else branches when shift is false.
    • While 1) actually compiles to a few more instructions than 2), the number of instructions executed when shift is either true or false, are equal for the two.
    • The instruction ordering for 1) is such that only one stack slot is occupied at all times, while 2) always loads two.

    做这些意见意味着条件运算符将执行慢?是否有其他的副作用即开始发挥作用?

    Do any of these observations imply that the conditional operator will perform slower? Is there other side-effects that come into play?

    推荐答案

    很奇怪,也许是.NET优化你的情况backfireing:

    Very odd, perhaps .NET optimization is backfireing in your case:

    笔者拆解数
      三元前pressions的版本,并
      发现,它们是相同的,以
      if语句,一个小
      区别。三元声明
      有时会产生code,它可以检测
      相反的情况,你会
      预计,在它测试的
      SUBEX pression是假的,而不是
      测试如果这是真的。这种重新排序
      一些指令和罐
      偶尔会提高性能。

    The author disassembled several versions of ternary expressions and found that they are identical to if-statements, with one small difference. The ternary statement sometimes produces code that tests the opposite condition that you would expect, as in it tests that the subexpression is false instead of testing if it is true. This reorders some of the instructions and can occasionally boost performance.

    http://dotnetperls.com/ternary

    您想可能会考虑在枚举值的ToString(对于非特殊情况):

    You want might consider the ToString on the enum value (for the non-special cases):

    string keyValue = inKey.ToString();
    return shift ? keyValue : keyValue.ToLower();
    

    编辑:结果
    我比较了如果其他方法向三元运营商,并与百万周期三元运算符总是至少一样快的if-else方法(有时几毫秒快,它支持上面的文字)。我认为你做了错误的somekind的测量花费的时间。


    I've compared the if-else method with the ternary operator and with 1000000 cycles the ternary operator is always at least as fast as the if-else method (sometimes a few millisec faster, which supports the text above). I think that you've made somekind of error in measuring the time it took.

    这篇关于是条件运算慢?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

    查看全文
    登录 关闭
    扫码关注1秒登录
    发送“验证码”获取 | 15天全站免登陆