2011-11-17 114 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<>因为泛型列表处理值类型,而拳击的代码。除非共享代码,否则无法提供帮助。