2011-11-17 116 views
0

我有添加〜100,000項到列表的代碼。列表<struct[]>。添加對列表<string[]>。添加或列表<object[]>。添加性能

如果我添加一個字符串或對象數組,代碼幾乎立即運行(在100毫秒以下),但是如果我嘗試添加一個結構數組,它僅需要1.5秒就可以完成.Add調用。

爲什麼使用struct []會有這樣的性能影響?

這裏是我的結構:

public struct LiteRowInfo 
{ 
    public long Position; 
    public int Length; 
    public int Field; 
    public int Row; 

    public LiteRowInfo(long position, int length, int field, int row) 
    { 
     this.Position = position; 
     this.Length = length; 
     this.Field = field; 
     this.Row = row; 
    } 
} 

編輯2:字符串方法的性能比結構的速度更快: 我很欣賞的評論,它似乎像有在創建結構額外開銷它的自我。我想我會創建2個單獨的列表來存儲位置和長度以提高性能。

private void Test() 
    { 
     Stopwatch watch = new Stopwatch(); 

     watch.Start(); 
     List<LiteRowInfo[]> structList = new List<LiteRowInfo[]>(); 

     for (int i = 0; i < 100000; i++) 
     { 
      LiteRowInfo[] info = new LiteRowInfo[20]; 

      for (int x = 0; x < 20; x++) 
      { 
       LiteRowInfo row; 
       row.Length = x; 
       row.Position = (long)i; 
       info[x] = row; 
      } 
      structList.Add(info); 
     } 
     Debug.Print(watch.ElapsedMilliseconds.ToString()); 

     watch.Reset(); 
     watch.Start(); 

     List<string[]> stringList = new List<string[]>(); 

     for (int i = 0; i < 100000; i++) 
     { 
      string[] info = new string[20]; 

      for (int x = 0; x < 20; x++) 
      { 
       info[x] = "String"; 
      } 
      stringList.Add(info); 
     } 

     Debug.Print(watch.ElapsedMilliseconds.ToString()); 
    } 

編輯:這裏是所有相關代碼: 注:如果我註釋掉只有pos.Add(rowInfo);行,其性能與字符串[]或int []相似。

 private void executeSqlStream() 
    { 
     List<LiteRowInfo[]> pos = new List<LiteRowInfo[]>(); 

     long currentPos = 0; 

     _stream = new MemoryStream(); 
     StreamWriter writer = new StreamWriter(_stream); 

     using (SqlConnection cnn = new SqlConnection(_cnnString)) 
     { 
      cnn.Open(); 
      SqlCommand cmd = new SqlCommand(_sqlString, cnn); 

      SqlDataReader reader = cmd.ExecuteReader(); 

      int fieldCount = reader.FieldCount; 
      int rowNum = 0; 
      UnicodeEncoding encode = new UnicodeEncoding(); 
      List<string> fields = new List<string>(); 
      for (int i = 0; i < fieldCount; i++) 
      { 
       fields.Add(reader.GetFieldType(i).Name); 
      } 
      while (reader.Read()) 
      { 
       LiteRowInfo[] rowData = new LiteRowInfo[fieldCount]; 
       for (int i = 0; i < fieldCount; i++) 
       { 
        LiteRowInfo info; 
        if (reader[i] != DBNull.Value) 
        { 
         byte[] b; 
         switch (fields[i]) 
         { 
          case "Int32": 
           b = BitConverter.GetBytes(reader.GetInt32(i)); 
           break; 
          case "Int64": 
           b = BitConverter.GetBytes(reader.GetInt64(i)); 
           break; 
          case "DateTime": 
           DateTime dt = reader.GetDateTime(i); 
           b = BitConverter.GetBytes(dt.ToBinary()); 
           break; 
          case "Double": 
           b = BitConverter.GetBytes(reader.GetDouble(i)); 
           break; 
          case "Boolean": 
           b = BitConverter.GetBytes(reader.GetBoolean(i)); 
           break; 
          case "Decimal": 
           b = BitConverter.GetBytes((float)reader.GetDecimal(i)); 
           break; 
          default: 
           b = encode.GetBytes(reader.GetString(i)); 
           break; 
         } 
         int len = b.Length; 

         info.Position = currentPos += len; 
         info.Length = len; 
         info.Field = i; 
         info.Row = rowNum; 
         currentPos += len; 
         _stream.Write(b, 0, len); 
        } 
        else 
        { 
         info.Position = currentPos; 
         info.Length = 0; 
         info.Field = i; 
         info.Row = rowNum; 
        } 
        rowData[i] = info; 
       } 
       rowNum++; 
       pos.Add(rowData); 
      } 
     } 
    } 
+4

你的結構有20個字節的開銷;任何類只會有IntPtr大小的開銷。 – ildjarn

+0

那麼你需要首先創建一個包含所有成員的結構,或者你可以在哪裏創建代碼並將結構添加到列表中? –

+0

可能是因爲您的代碼在將結構添加到列表之前需要裝箱。嘗試共享添加到列表中的代碼。 – driis

回答

8

鑑於數組本身是一個引用類型,我非常懷疑你實際上看到了你認爲你看到的是什麼。

我懷疑差異不是在列表中添加數組引用 - 我懷疑它是首先創建數組。每個數組元素將比引用佔用更多的空間,所以你不得不分配更多的內存。這可能意味着你的也觸發垃圾回收

爲基準只是List<T>.Add,我建議你反覆添加到相同陣列多次引用。

順便說一句,有一個數組作爲列表元素類型感覺有點像我的氣味。有時候這是有效的,但是我個人會考慮它是否實際上可以封裝在另一種類型中。

編輯:你說你已經發布的所有相關的代碼,但真的不是基準代碼List<T>.Add - 它包含了一兩件事,這幾乎肯定是服用的方式比任何不再數據庫訪問內存中的操作!

+1

+1:註釋'pos.Add(rowInfo)'使事情變得更快的原因是編譯器能夠識別rowInfo未被使用,所以它優化了結構數組的創建。 – StriplingWarrior

+0

感謝Jon,我沒有看到我認爲我看到的是什麼:)。 – ChandlerPelhams

+0

@StriplingWarrior - 對於大幅性能增益的很好解釋,謝謝。 – ChandlerPelhams

0

可能有一些拳擊發生在這無關List<>因爲泛型列表處理值類型,而拳擊的代碼。除非共享代碼,否則無法提供幫助。