2016-11-25 74 views
0

我創建了一個TypeSwitch類使用類似於下面的縮短樣品代碼投我的領域:令人驚訝的糟糕C#開關性能

static Dictionary<Type, int> TypeDefs = new Dictionary<Type, int>() 
{ 
    {typeof(Int16), 1}, 
    {typeof(Int32), 2}, 
    {typeof(Int64), 3}, 
    {typeof(IntPtr), 4}, 
    ... 
    {typeof(String), 18} 
}; 

public static object ConvertFromDBValue(Type type, object value) 
{ 
    try 
    { 
     switch (TypeDefs[type]) 
     { 
      case 1: // {typeof(Int16), 1}, 
      { 
       return Convert.ToInt16(value); 
      } 
      case 2: // {typeof(Int32), 2}, 
      { 
       return Convert.ToInt32(value); 
      } 
      case 3: // {typeof(Int64), 3}, 
      { 
       return Convert.ToInt64(value); 
      } 
      ... 
      ... 
      ... 
      case 17: // {typeof(Char), 17}, 
      case 18: // {typeof(String), 18}, 
      { 
       return value.ToString().Trim(); 
      } 
      default: 
      { 
       return value; 
      } 
     } 
    } 
    catch (Exception ex) 
    { 
     throw ex; 
    } 
} 

使用儀器儀表工具,我看的時候超過60%是花在上面的ConvertFromDBValue的函數體,即我花費更多的時間因爲切換(或try-catch)而不是查找Dictionary.get_Item中的Type值並轉換該值(例如Convert.ToInt32)。實際上,我在功能體中花費的時間比Dictionary.get_Item多3倍..​​.

這對我來說有些令人驚訝 - 任何人都可以確認switch慢得多,或者是否有其他原因?

UPDATE 我刪除的try-catch一部分,但是這並沒有真的多...

+0

我懷疑它的'之開關,減慢你失望。我懷疑這是需要時間的價值的拳擊。如果你的字典是強類型的,那麼它將工作得非常快。 –

+0

交換機應該是很快的。這取決於。你稱這種方法有多少次?不要一遍又一遍地使用try-catch,因爲這太慢了。 –

+1

BTW :(與你的性能問題無關)像Dictionary >這樣的字典可以是一個簡潔的解決方案,它可以避免使用* switch * .... **'Dictionary > TypeDefs = new Dictionary >(){typeof(Int16),x => Convert.ToInt16(x)}, {typeof(String), x => x.ToString()。Trim()} }; var val = TypeDefs [typeof(short)](「12345」);'** –

回答

-1

下面是一些示例代碼,如果我「的功能和數組索引挑陣」是不明確的。

Func<object, object>[] funcList = 
    { (value) => value,     //0 
    (value) => Convert.ToInt16(value), //1 
    (value) => Convert.ToInt32(value), //2 
    (value) => Convert.ToInt64(value), //3 
    (value) => value, //4 
    (value) => value, //5 
    (value) => value, //6 
    (value) => value, //7 
    (value) => value, //8 
    (value) => value, //9 
    (value) => value, //10 
    (value) => value, //11 
    (value) => value, //12 
    (value) => value, //13 
    (value) => value, //14 
    (value) => value, //15 
    (value) => value, //16 
    (value) => value, //17 
    (value) => value.ToString().Trim() //18 
    }; 

public static object ConvertFromDBValue(Type type, object value) 
{ 
    if (TypeDefs[type] <= 18) 
    return funcList[TypeDefs[type]](value); 
    else 
    return value; 
} 

爲了使這個更快的if語句拿出if (TypeDefs[type] <= 18)如果你能保證不存在值大於18

這是樣品未測試的代碼。

+3

'TypeDefs + funcList'只是爲了得到一個委託?爲什麼不簡單地在我的評論中使用字典作爲一個說法呢? 'var val = TypeDefs [typeof(short)](「12345」)' –

+0

實際上是一個反投票,因爲有兩個字典訪問調用這個方法...... – neggenbe

+0

@neggenbe - 任何優化器只會在這裏打一個電話。 – Hogan

0

正如其他人提到你正在支付拳擊/拆箱罰款,如果可能你應該嘗試消除它。

至於方法的主體,你應該擺脫字典,並使用鏈如果if elses - 它應該給你一個可衡量的性能提高。


編輯

後霍根的評論我測試過它,讓我吃驚的差異字典+抓之間VS 如果小於5%之間-15%(如果是稍微快一點)在我下面的不完美測試中。

Dict+case: 987.0945ms 
Ifs: 937.5104ms 
Hogan's array of funcs: 854.4887ms 

測試:

class Program 
{ 
    static Dictionary<Type, int> TypeDefs = new Dictionary<Type, int>() 
    { 
     {typeof(Int16), 1}, 
     {typeof(Int32), 2}, 
     {typeof(Int64), 3}, 
     {typeof(IntPtr), 4}, 
     {typeof(char), 5}, 
     {typeof(String), 6} 
    }; 

    static KeyValuePair<Type,object>[] _Types = new[] 
     { new KeyValuePair<Type,object> (typeof(Int16),5), 
     new KeyValuePair<Type,object> (typeof(Int32),57), 
     new KeyValuePair<Type,object> (typeof(Int64),157), 
     new KeyValuePair<Type,object> (typeof(IntPtr),new IntPtr(6)), 
     new KeyValuePair<Type,object> (typeof(String),"Hello!"), 
    }; 

    public static object ConvertFromDBValue(Type type, object value) 
    { 
     try 
     { 
      switch (TypeDefs[type]) 
      { 
       case 1: // {typeof(Int16), 1}, 
        { 
         return Convert.ToInt16(value); 
        } 
       case 2: // {typeof(Int32), 2}, 
        { 
         return Convert.ToInt32(value); 
        } 
       case 3: // {typeof(Int64), 3}, 
        { 
         return Convert.ToInt64(value); 
        } 
       case 4: // {typeof(IntPtr), 4}, 
        { 
         return value; 
        } 
       case 5: // {typeof(Char), 17}, 
       case 6: // {typeof(String), 18}, 
        { 
         return value; 
        } 
       default: 
        { 
         return value; 
        } 
      } 
     } 
     catch (Exception ex) 
     { 
      throw ex; 
     } 
    } 

    public static object ConvertFromDBValue2(Type type, object value) 
    { 
     try 
     { 
      if (type == typeof(Int16)) 
      { 
       return Convert.ToInt16(value); 
      } 
      if (type == typeof(Int32)) 
      { 
       return Convert.ToInt32(value); 
      } 
      if (type == typeof(Int64)) 
      { 
       return Convert.ToInt64(value); 
      } 
      if (type == typeof(IntPtr)) 
      { 
       return (IntPtr)value; 
      } 
      if (type == typeof(Char) || type == typeof(String)) 
      { 
       return value.ToString().Trim(); 
      } 
      return value; 
     } 
     catch (Exception ex) 
     { 
      throw ex; 
     } 
    } 


    static Func<object, object>[] funcList = 
    { 
     (value) => value,     //0 
     (value) => Convert.ToInt16(value), //1 
     (value) => Convert.ToInt32(value), //2 
     (value) => Convert.ToInt64(value), //3 
     (value) => value, //4 
     (value) => value, //5 
     (value) => value, //6 
     (value) => value, //7 
     (value) => value, //8 
     (value) => value, //9 
     (value) => value, //10 
     (value) => value, //11 
     (value) => value, //12 
     (value) => value, //13 
     (value) => value, //14 
     (value) => value, //15 
     (value) => value, //16 
     (value) => value, //17 
     (value) => value.ToString().Trim() //18 
    }; 

    public static object ConvertFromDBValueHogan(Type type, object value) 
    { 
    return funcList[TypeDefs[type]](value); 
    } 

    static void Main(string[] args) 
    { 
     var sw = new System.Diagnostics.Stopwatch(); 
     Random random = new Random(113453113); 


     sw.Start(); 
     for (int i = 0; i < 10000000; i++) 
     { 
      var x = random.Next(5); 
      var testValue = _Types[x]; 
      var p = ConvertFromDBValue(testValue.Key, testValue.Value); 
     } 
     var elapsed = sw.Elapsed; 
     Console.WriteLine($"Dict+case: {elapsed.TotalMilliseconds}ms"); 

     sw.Restart(); 
     for (int i = 0; i < 10000000; i++) 
     { 
      var x = random.Next(5); 
      var testValue = _Types[x]; 
      var p2 = ConvertFromDBValue2(testValue.Key, testValue.Value); 
     } 
     elapsed = sw.Elapsed; 
     Console.WriteLine($"Ifs: {elapsed.TotalMilliseconds}ms"); 

     sw.Restart(); 
     for (int i = 0; i < 10000000; i++) 
     { 
      var x = random.Next(5); 
      var testValue = _Types[x]; 
      var p3 = ConvertFromDBValueHogan(testValue.Key, testValue.Value); 
     } 
     elapsed = sw.Elapsed; 
     Console.WriteLine($"Hogan's array of funcs: {elapsed.TotalMilliseconds}ms"); 
     Console.ReadLine(); 
    } 
} 
+0

好吧,我會嘗試 - 我明白了 - 對於列表末尾的項目,「if-else」速度較慢,但​​字典訪問速度更快......至於拳擊,我打開了一個關於它的新問題[在這裏](http://stackoverflow.com/questions/40812841/improve-efficiency-of-database-row-reading-without-boxing)... – neggenbe

+0

這是錯誤的字典應該比chained更快,如果其他和切換 - 除非你瞭解頻率。 – Hogan

相關問題