代码之家  ›  专栏  ›  技术社区  ›  Quibblesome

什么更快,打开字符串或Elseif打开类型?

  •  72
  • Quibblesome  · 技术社区  · 16 年前

    假设我可以选择识别代码路径,以便根据字符串比较或其他类型进行区分:

    哪个更快,为什么?

    switch(childNode.Name)
    {
        case "Bob":
          break;
        case "Jill":
          break;
        case "Marko":
          break;
    }
    
    if(childNode is Bob)
    {
    }
    elseif(childNode is Jill)
    {
    }
    else if(childNode is Marko)
    {
    }
    

    更新: 我之所以问这个问题,主要是因为switch语句是Perculiar关于什么才算是一个案例。例如,它不允许您使用变量,只允许将常量移动到主程序集。我认为这是因为它所做的一些奇怪的事情。如果它只是翻译成elseifs(正如一个海报所评论的那样),那么为什么在case语句中不允许变量?

    Caveat: 我正在进行后期优化。此方法被调用 许多的 在应用程序的慢速部分的时间。

    23 回复  |  直到 16 年前
        1
  •  121
  •   Mani Gandham    7 年前

    int value = 25124;
    if(value == 0) ...
    else if (value == 1) ...
    else if (value == 2) ...
    ...
    else if (value == 25124) ... 
    

    switch(value) {
     case 0:...break;
     case 1:...break;
     case 2:...break;
     ...
     case 25124:...break;
    }
    

    switch(someString) {
        case "Foo": DoFoo(); break;
        case "Bar": DoBar(); break;
        default: DoOther; break;
    }
    

    if(someString == "Foo") {
        DoFoo();
    } else if(someString == "Bar") {
        DoBar();
    } else {
        DoOther();
    }
    

    Dictionary<string, int>

    //Make sure the dictionary is loaded
    if(theDictionary == null) { 
        //This is simplified for clarity, the actual implementation is more complex 
        // in order to ensure thread safety
        theDictionary = new Dictionary<string,int>();
        theDictionary["Foo"] = 0;
        theDictionary["Bar"] = 1;
    }
    
    int switchIndex;
    if(theDictionary.TryGetValue(someString, out switchIndex)) {
        switch(switchIndex) {
        case 0: DoFoo(); break;
        case 1: DoBar(); break;
        }
    } else {
        DoOther();
    }
    

    private delegate void NodeHandler(ChildNode node);
    
    static Dictionary<RuntimeTypeHandle, NodeHandler> TypeHandleSwitcher = CreateSwitcher();
    
    private static Dictionary<RuntimeTypeHandle, NodeHandler> CreateSwitcher()
    {
        var ret = new Dictionary<RuntimeTypeHandle, NodeHandler>();
    
        ret[typeof(Bob).TypeHandle] = HandleBob;
        ret[typeof(Jill).TypeHandle] = HandleJill;
        ret[typeof(Marko).TypeHandle] = HandleMarko;
    
        return ret;
    }
    
    void HandleChildNode(ChildNode node)
    {
        NodeHandler handler;
        if (TaskHandleSwitcher.TryGetValue(Type.GetRuntimeType(node), out handler))
        {
            handler(node);
        }
        else
        {
            //Unexpected type...
        }
    }
    

    Testing 3 iterations with 5,000,000 data elements (mode=Random) and 5 types
    Method                Time    % of optimal
    If/Else               179.67  100.00
    TypeHandleDictionary  321.33  178.85
    TypeDictionary        377.67  210.20
    Switch                492.67  274.21
    
    Testing 3 iterations with 5,000,000 data elements (mode=Random) and 10 types
    Method                Time    % of optimal
    If/Else               271.33  100.00
    TypeHandleDictionary  312.00  114.99
    TypeDictionary        374.33  137.96
    Switch                490.33  180.71
    
    Testing 3 iterations with 5,000,000 data elements (mode=Random) and 15 types
    Method                Time    % of optimal
    TypeHandleDictionary  312.00  100.00
    If/Else               369.00  118.27
    TypeDictionary        371.67  119.12
    Switch                491.67  157.59
    
    Testing 3 iterations with 5,000,000 data elements (mode=Random) and 20 types
    Method                Time    % of optimal
    TypeHandleDictionary  335.33  100.00
    TypeDictionary        373.00  111.23
    If/Else               462.67  137.97
    Switch                490.33  146.22
    
    Testing 3 iterations with 5,000,000 data elements (mode=Random) and 25 types
    Method                Time    % of optimal
    TypeHandleDictionary  319.33  100.00
    TypeDictionary        371.00  116.18
    Switch                483.00  151.25
    If/Else               562.00  175.99
    
    Testing 3 iterations with 5,000,000 data elements (mode=Random) and 50 types
    Method                Time      % of optimal
    TypeHandleDictionary  319.67    100.00
    TypeDictionary        376.67    117.83
    Switch                453.33    141.81
    If/Else               1,032.67  323.04
    
    

    Testing 3 iterations with 5,000,000 data elements (mode=UniformFirst) and 50 types
    Method                Time    % of optimal
    If/Else               39.00   100.00
    TypeHandleDictionary  317.33  813.68
    TypeDictionary        396.00  1,015.38
    Switch                403.00  1,033.33
    

    Testing 3 iterations with 5,000,000 data elements (mode=UniformLast) and 50 types
    Method                Time      % of optimal
    TypeHandleDictionary  317.67    100.00
    Switch                354.33    111.54
    TypeDictionary        377.67    118.89
    If/Else               1,907.67  600.52
    

        2
  •  18
  •   Greg    16 年前


    class Program
    {
        static void Main( string[] args )
        {
            Bob bob = new Bob();
            Jill jill = new Jill();
            Marko marko = new Marko();
    
            for( int i = 0; i < 1000000; i++ )
            {
                Test( bob );
                Test( jill );
                Test( marko );
            }
        }
    
        public static void Test( ChildNode childNode )
        {   
            TestSwitch( childNode );
            TestIfElse( childNode );
        }
    
        private static void TestIfElse( ChildNode childNode )
        {
            if( childNode is Bob ){}
            else if( childNode is Jill ){}
            else if( childNode is Marko ){}
        }
    
        private static void TestSwitch( ChildNode childNode )
        {
            switch( childNode.Name )
            {
                case "Bob":
                    break;
                case "Jill":
                    break;
                case "Marko":
                    break;
            }
        }
    }
    
    class ChildNode { public string Name { get; set; } }
    
    class Bob : ChildNode { public Bob(){ this.Name = "Bob"; }}
    
    class Jill : ChildNode{public Jill(){this.Name = "Jill";}}
    
    class Marko : ChildNode{public Marko(){this.Name = "Marko";}}
    
        3
  •  17
  •   ilitirit    16 年前

    class Node
    {
        public virtual void Action()
        {
            // Perform default action
        }
    }
    
    class Bob : Node
    {
        public override void Action()
        {
            // Perform action for Bill
        }
    }
    
    class Jill : Node
    {
        public override void Action()
        {
            // Perform action for Jill
        }
    }
    

        4
  •  12
  •   Nescio    16 年前

        5
  •  6
  •   Gary Kephart    16 年前

        6
  •  4
  •   Rick Minerich    16 年前

        7
  •  3
  •   Chris Upchurch    16 年前

        8
  •  3
  •   user17983    16 年前

        9
  •  3
  •   Ted Elliott    16 年前

    Dictionary<Type, HandlerDelegate> handlers = new Dictionary<Type, HandlerDelegate>();
    handlers[typeof(Bob)] = this.HandleBob;
    handlers[typeof(Jill)] = this.HandleJill;
    handlers[typeof(Marko)] = this.HandleMarko;
    
    handlers[childNode.GetType()](childNode);
    /// ...
    
    private void HandleBob(Node childNode) {
        // code to handle Bob
    }
    
        10
  •  2
  •   moonshadow    16 年前

        12
  •  2
  •   SaguiItay    16 年前

    switch(childNode.Name)
    {
        case "Bob":
            break;
        case "Jill":
            break;
        case "Marko":
          break;
    }
    
    if(childNode.Name == "Bob")
    {}
    else if(childNode.Name == "Jill")
    {}
    else if(childNode.Name == "Marko")
    {}
    
        13
  •  2
  •   nawfal Donny V.    11 年前

    interface INode
    {
        void Action;
    }
    
    class Bob : INode
    {
        public void Action
        {
    
        }
    }
    
    class Jill : INode
    {
        public void Action
        {
    
        }
    }
    
    class Marko : INode
    {
        public void Action
        {
    
        }
    }
    
    //Your function:
    void Do(INode childNode)
    {
        childNode.Action();
    }
    

    enum NodeType { Bob, Jill, Marko, Default }
    
    interface INode
    {
        NodeType Node { get; };
    }
    
    class Bob : INode
    {
        public NodeType Node { get { return NodeType.Bob; } }
    }
    
    class Jill : INode
    {
        public NodeType Node { get { return NodeType.Jill; } }
    }
    
    class Marko : INode
    {
        public NodeType Node { get { return NodeType.Marko; } }
    }
    
    //Your function:
    void Do(INode childNode)
    {
        switch(childNode.Node)
        {
            case Bob:
              break;
            case Jill:
              break;
            case Marko:
              break;
            Default:
              throw new ArgumentException();
        }
    }
    

    if nanoseconds does matter for you

        14
  •  2
  •   Walter Verhoeven    6 年前

    Core 2 console app with output

      public static class StringExtention
        {
            public static long ToUniqueHash(this string text)
            {
                long value = 0;
                var array = text.ToCharArray();
                unchecked
                {
                    for (int i = 0; i < array.Length; i++)
                    {
                        value = (value * 397) ^ array[i].GetHashCode();
                        value = (value * 397) ^ i;
                    }
                    return value;
                }
            }
        }
    
        public class AccountTypes
        {
    
            static void Main()
            {
                var sb = new StringBuilder();
    
                sb.AppendLine($"const long ACCOUNT_TYPE = {"AccountType".ToUniqueHash()};");
                sb.AppendLine($"const long NET_LIQUIDATION = {"NetLiquidation".ToUniqueHash()};");
                sb.AppendLine($"const long TOTAL_CASH_VALUE = {"TotalCashValue".ToUniqueHash()};");
                sb.AppendLine($"const long SETTLED_CASH = {"SettledCash".ToUniqueHash()};");
                sb.AppendLine($"const long ACCRUED_CASH = {"AccruedCash".ToUniqueHash()};");
                sb.AppendLine($"const long BUYING_POWER = {"BuyingPower".ToUniqueHash()};");
                sb.AppendLine($"const long EQUITY_WITH_LOAN_VALUE = {"EquityWithLoanValue".ToUniqueHash()};");
                sb.AppendLine($"const long PREVIOUS_EQUITY_WITH_LOAN_VALUE = {"PreviousEquityWithLoanValue".ToUniqueHash()};");
                sb.AppendLine($"const long GROSS_POSITION_VALUE ={ "GrossPositionValue".ToUniqueHash()};");
                sb.AppendLine($"const long REQT_EQUITY = {"ReqTEquity".ToUniqueHash()};");
                sb.AppendLine($"const long REQT_MARGIN = {"ReqTMargin".ToUniqueHash()};");
                sb.AppendLine($"const long SPECIAL_MEMORANDUM_ACCOUNT = {"SMA".ToUniqueHash()};");
                sb.AppendLine($"const long INIT_MARGIN_REQ = { "InitMarginReq".ToUniqueHash()};");
                sb.AppendLine($"const long MAINT_MARGIN_REQ = {"MaintMarginReq".ToUniqueHash()};");
                sb.AppendLine($"const long AVAILABLE_FUNDS = {"AvailableFunds".ToUniqueHash()};");
                sb.AppendLine($"const long EXCESS_LIQUIDITY = {"ExcessLiquidity".ToUniqueHash()};");
                sb.AppendLine($"const long CUSHION = {"Cushion".ToUniqueHash()};");
                sb.AppendLine($"const long FULL_INIT_MARGIN_REQ = {"FullInitMarginReq".ToUniqueHash()};");
                sb.AppendLine($"const long FULL_MAINTMARGIN_REQ ={ "FullMaintMarginReq".ToUniqueHash()};");
                sb.AppendLine($"const long FULL_AVAILABLE_FUNDS = {"FullAvailableFunds".ToUniqueHash()};");
                sb.AppendLine($"const long FULL_EXCESS_LIQUIDITY ={ "FullExcessLiquidity".ToUniqueHash()};");
                sb.AppendLine($"const long LOOK_AHEAD_INIT_MARGIN_REQ = {"LookAheadInitMarginReq".ToUniqueHash()};");
                sb.AppendLine($"const long LOOK_AHEAD_MAINT_MARGIN_REQ = {"LookAheadMaintMarginReq".ToUniqueHash()};");
                sb.AppendLine($"const long LOOK_AHEAD_AVAILABLE_FUNDS = {"LookAheadAvailableFunds".ToUniqueHash()};");
                sb.AppendLine($"const long LOOK_AHEAD_EXCESS_LIQUIDITY = {"LookAheadExcessLiquidity".ToUniqueHash()};");
                sb.AppendLine($"const long HIGHEST_SEVERITY = {"HighestSeverity".ToUniqueHash()};");
                sb.AppendLine($"const long DAY_TRADES_REMAINING = {"DayTradesRemaining".ToUniqueHash()};");
                sb.AppendLine($"const long LEVERAGE = {"Leverage".ToUniqueHash()};");
                Console.WriteLine(sb.ToString());
    
                Test();    
            }    
    
            public static void Test()
            {
                //generated constant values
                const long ACCOUNT_TYPE = -3012481629590703298;
                const long NET_LIQUIDATION = 5886477638280951639;
                const long TOTAL_CASH_VALUE = 2715174589598334721;
                const long SETTLED_CASH = 9013818865418133625;
                const long ACCRUED_CASH = -1095823472425902515;
                const long BUYING_POWER = -4447052054809609098;
                const long EQUITY_WITH_LOAN_VALUE = -4088154623329785565;
                const long PREVIOUS_EQUITY_WITH_LOAN_VALUE = 6224054330592996694;
                const long GROSS_POSITION_VALUE = -7316842993788269735;
                const long REQT_EQUITY = -7457439202928979430;
                const long REQT_MARGIN = -7525806483981945115;
                const long SPECIAL_MEMORANDUM_ACCOUNT = -1696406879233404584;
                const long INIT_MARGIN_REQ = 4495254338330797326;
                const long MAINT_MARGIN_REQ = 3923858659879350034;
                const long AVAILABLE_FUNDS = 2736927433442081110;
                const long EXCESS_LIQUIDITY = 5975045739561521360;
                const long CUSHION = 5079153439662500166;
                const long FULL_INIT_MARGIN_REQ = -6446443340724968443;
                const long FULL_MAINTMARGIN_REQ = -8084126626285123011;
                const long FULL_AVAILABLE_FUNDS = 1594040062751632873;
                const long FULL_EXCESS_LIQUIDITY = -2360941491690082189;
                const long LOOK_AHEAD_INIT_MARGIN_REQ = 5230305572167766821;
                const long LOOK_AHEAD_MAINT_MARGIN_REQ = 4895875570930256738;
                const long LOOK_AHEAD_AVAILABLE_FUNDS = -7687608210548571554;
                const long LOOK_AHEAD_EXCESS_LIQUIDITY = -4299898188451362207;
                const long HIGHEST_SEVERITY = 5831097798646393988;
                const long DAY_TRADES_REMAINING = 3899479916235857560;
                const long LEVERAGE = 1018053116254258495;
    
                bool found = false;
                var sValues = new string[] {
                  "AccountType"
                  ,"NetLiquidation"
                  ,"TotalCashValue"
                  ,"SettledCash"
                  ,"AccruedCash"
                  ,"BuyingPower"
                  ,"EquityWithLoanValue"
                  ,"PreviousEquityWithLoanValue"
                  ,"GrossPositionValue"
                  ,"ReqTEquity"
                  ,"ReqTMargin"
                  ,"SMA"
                  ,"InitMarginReq"
                  ,"MaintMarginReq"
                  ,"AvailableFunds"
                  ,"ExcessLiquidity"
                  ,"Cushion"
                  ,"FullInitMarginReq"
                  ,"FullMaintMarginReq"
                  ,"FullAvailableFunds"
                  ,"FullExcessLiquidity"
                  ,"LookAheadInitMarginReq"
                  ,"LookAheadMaintMarginReq"
                  ,"LookAheadAvailableFunds"
                  ,"LookAheadExcessLiquidity"
                  ,"HighestSeverity"
                  ,"DayTradesRemaining"
                  ,"Leverage"
                };
    
                long t1, t2;
                var sw = System.Diagnostics.Stopwatch.StartNew();
                foreach (var name in sValues)
                {
                    switch (name)
                    {
                        case "AccountType": found = true; break;
                        case "NetLiquidation": found = true; break;
                        case "TotalCashValue": found = true; break;
                        case "SettledCash": found = true; break;
                        case "AccruedCash": found = true; break;
                        case "BuyingPower": found = true; break;
                        case "EquityWithLoanValue": found = true; break;
                        case "PreviousEquityWithLoanValue": found = true; break;
                        case "GrossPositionValue": found = true; break;
                        case "ReqTEquity": found = true; break;
                        case "ReqTMargin": found = true; break;
                        case "SMA": found = true; break;
                        case "InitMarginReq": found = true; break;
                        case "MaintMarginReq": found = true; break;
                        case "AvailableFunds": found = true; break;
                        case "ExcessLiquidity": found = true; break;
                        case "Cushion": found = true; break;
                        case "FullInitMarginReq": found = true; break;
                        case "FullMaintMarginReq": found = true; break;
                        case "FullAvailableFunds": found = true; break;
                        case "FullExcessLiquidity": found = true; break;
                        case "LookAheadInitMarginReq": found = true; break;
                        case "LookAheadMaintMarginReq": found = true; break;
                        case "LookAheadAvailableFunds": found = true; break;
                        case "LookAheadExcessLiquidity": found = true; break;
                        case "HighestSeverity": found = true; break;
                        case "DayTradesRemaining": found = true; break;
                        case "Leverage": found = true; break;
                        default: found = false; break;
                    }
    
                    if (!found)
                        throw new NotImplementedException();
                }
                t1 = sw.ElapsedTicks;
                sw.Restart();
                foreach (var name in sValues)
                {
                    switch (name.ToUniqueHash())
                    {
                        case ACCOUNT_TYPE:
                            found = true;
                            break;
                        case NET_LIQUIDATION:
                            found = true;
                            break;
                        case TOTAL_CASH_VALUE:
                            found = true;
                            break;
                        case SETTLED_CASH:
                            found = true;
                            break;
                        case ACCRUED_CASH:
                            found = true;
                            break;
                        case BUYING_POWER:
                            found = true;
                            break;
                        case EQUITY_WITH_LOAN_VALUE:
                            found = true;
                            break;
                        case PREVIOUS_EQUITY_WITH_LOAN_VALUE:
                            found = true;
                            break;
                        case GROSS_POSITION_VALUE:
                            found = true;
                            break;
                        case REQT_EQUITY:
                            found = true;
                            break;
                        case REQT_MARGIN:
                            found = true;
                            break;
                        case SPECIAL_MEMORANDUM_ACCOUNT:
                            found = true;
                            break;
                        case INIT_MARGIN_REQ:
                            found = true;
                            break;
                        case MAINT_MARGIN_REQ:
                            found = true;
                            break;
                        case AVAILABLE_FUNDS:
                            found = true;
                            break;
                        case EXCESS_LIQUIDITY:
                            found = true;
                            break;
                        case CUSHION:
                            found = true;
                            break;
                        case FULL_INIT_MARGIN_REQ:
                            found = true;
                            break;
                        case FULL_MAINTMARGIN_REQ:
                            found = true;
                            break;
                        case FULL_AVAILABLE_FUNDS:
                            found = true;
                            break;
                        case FULL_EXCESS_LIQUIDITY:
                            found = true;
                            break;
                        case LOOK_AHEAD_INIT_MARGIN_REQ:
                            found = true;
                            break;
                        case LOOK_AHEAD_MAINT_MARGIN_REQ:
                            found = true;
                            break;
                        case LOOK_AHEAD_AVAILABLE_FUNDS:
                            found = true;
                            break;
                        case LOOK_AHEAD_EXCESS_LIQUIDITY:
                            found = true;
                            break;
                        case HIGHEST_SEVERITY:
                            found = true;
                            break;
                        case DAY_TRADES_REMAINING:
                            found = true;
                            break;
                        case LEVERAGE:
                            found = true;
                            break;
                        default:
                            found = false;
                            break;
                    }
    
                    if (!found)
                        throw new NotImplementedException();
                }
                t2 = sw.ElapsedTicks;
                sw.Stop();
                Console.WriteLine($"String switch:{t1:N0} long switch:{t2:N0}");
                var faster = (t1 > t2) ? "Slower" : "faster";
                Console.WriteLine($"String switch: is {faster} than long switch: by {Math.Abs(t1-t2)} Ticks");
                Console.ReadLine();
    
            }
    
        15
  •  0
  •   Magsol    16 年前

        16
  •  0
  •   JeeBee    16 年前

        17
  •  0
  •   Mark Bessey    16 年前

        19
  •  0
  •   Eddie Velasquez    16 年前
        20
  •  0
  •   nimish    16 年前

        21
  •  0
  •   Walter Verhoeven    6 年前

    //somewhere in your code
    static long _bob = "Bob".GetUniqueHashCode();
    static long _jill = "Jill".GetUniqueHashCode();
    static long _marko = "Marko".GeUniquetHashCode();
    
    void MyMethod()
    {
       ...
       if(childNode.Tag==0)
          childNode.Tag= childNode.Name.GetUniquetHashCode()
    
       switch(childNode.Tag)
       {
           case _bob :
            break;
           case _jill :
             break;
           case _marko :
            break;
       }
    }
    

    public static class StringExtentions
        {
            /// <summary>
            /// Return unique Int64 value for input string
            /// </summary>
            /// <param name="strText"></param>
            /// <returns></returns>
            public static Int64 GetUniquetHashCode(this string strText)
            {
                Int64 hashCode = 0;
                if (!string.IsNullOrEmpty(strText))
                {
                    //Unicode Encode Covering all character-set
                    byte[] byteContents = Encoding.Unicode.GetBytes(strText);
                    System.Security.Cryptography.SHA256 hash =  new System.Security.Cryptography.SHA256CryptoServiceProvider();
                    byte[] hashText = hash.ComputeHash(byteContents);
                    //32Byte hashText separate
                    //hashCodeStart = 0~7  8Byte
                    //hashCodeMedium = 8~23  8Byte
                    //hashCodeEnd = 24~31  8Byte
                    //and Fold
                    Int64 hashCodeStart = BitConverter.ToInt64(hashText, 0);
                    Int64 hashCodeMedium = BitConverter.ToInt64(hashText, 8);
                    Int64 hashCodeEnd = BitConverter.ToInt64(hashText, 24);
                    hashCode = hashCodeStart ^ hashCodeMedium ^ hashCodeEnd;
                }
                return (hashCode);
            }
    
    
        }
    

    here

        22
  •  0
  •   Thrawn Wannabe    6 年前

    this benchmark test switch if-else ?

    that post if-else-if-else

        23
  •  -1
  •   Aeon    16 年前

    switch(childNode.Type)
    {
    case Bob:
      break;
    case Jill:
      break;
    case Marko:
      break;
    }