2011-11-17 25 views
0

リストに〜100,000個のアイテムを追加するコードがあります。リスト<struct[]>。追加とリスト<string[]> .Addまたはリスト<object[]>。パフォーマンスを追加

文字列またはオブジェクトの配列を追加すると、コードはほとんど瞬時に(100ミリ秒未満)実行されますが、構造体の配列を追加しようとすると.Add呼び出しのためにほぼ1.5秒かかります。

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; 
    } 
} 

EDIT 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()); 
    } 

EDIT: 注:ここでは、関連するすべてのコードは、私が唯一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に、私はあなたが繰り返し同じ配列数回に参照を追加することを示唆しています。

リスト要素型として配列を持つことは、私にはちょっとした匂いのように感じます。それが有効な時がありますが、個人的には、実際に別のタイプにカプセル化できるものかどうかを検討します。

EDIT:あなたは、関連するすべてのコードを掲載しましたと言うが、それ本当にList<T>.Addのベンチマークのコードではありません - それは一つのことのためのデータベースへのアクセスが含まれ、ほぼ確実のいずれよりも長い方法を取っていますメモリ内操作!

+1

+1:pos.Add(rowInfo)をコメントアウトする理由は、コンパイラがrowInfoが使用されていないことを認識できるため、構造体配列の作成を最適化するためです。 – StriplingWarrior

+0

ありがとうジョン、私は私が見ていたと思っているものを見ていなかった:)。 – ChandlerPelhams

+0

@ StriplingWarrior - 大きなパフォーマンスの向上、良いおかげで良い説明。 – ChandlerPelhams

0

ジェネリックリストはボクシングせずに値型を扱うので、List<>を関連していないコードで起こっていくつかのボクシングがあるかもしれません。コードを共有しない限り、助けてはいけません。

関連する問題