3

データベースから 100 万行ほどの潜在的な行をループするのに時間の問題があります。私は基本的に行を DataTable にプルし、それらをループしますが、遅くなります。そこに代わるものは何ですか?この行を 20,000 個のチャンクに分割できます。C# で並列処理を使用できますか? 基本的に、コードは特定のクエリに一致する可能性のあるすべてのレコードをループし、それが正当なエントリであるかどうかを判断しようとします。そのため、すべてのレコードを個別に参照する必要があります。1 つのオブジェクトのレコードは 1,000 万行に達する可能性があります。アプローチは、複数のコンピューターまたは複数のコアを備えた単一のマシンでの PP での並列処理のように見えますか、または何らかのデータ構造/アプローチの変更ですか?

これを迅速かつ合理的にするために役立つ意見、考え、推測はありますか?

4

2 に答える 2

2

まず最初に:次のような操作には使用しないでくださいDataTable

  • 遅い
  • あまりにも多くのメモリを消費しています
  • 実際にデータの処理を開始する前に、長時間待つ必要があります
    • この間、データのaへの読み取りは並列化されないため、追加のコアは何もしDataTableません。
    • また、データの読み取り中は、ネットワークまたはその他のI / O遅延が主な要因となることが多いため、CPUは通常ほとんど使用されていません。

繰り返しになりますが、このような操作には使用しないでくださいDataTable

代わりに。を使用してDataReaderください。これにより、データがロードされるのを待つのではなく、データの消費/処理をすぐに開始できます。最も単純なバージョンは次のとおりです(MS SQL Serverのサンプル):

var command = new SqlCommand()
{
  CommandText = "SELECT * FROM Table";
  Connection = new SqlConnection("InsertConnectionString");
};

using(var reader = command.ExecuteReader())
{
  while(reader.Read())
  {
    var values = new object[reader.FieldCount];
    reader.GetValues(values);

    // process values of row
  }
}

処理コードの実行中はリーダーがブロックされます。つまり、DBから行が読み取られなくなります。
処理コードが重い場合は、Taskライブラリを使用してチェックを実行するタスクを作成することをお勧めします。これにより、複数のコアを利用できるようになります。ただし、作成のオーバーヘッドがあります。十分な「作業」が含まれていないTask場合は、いくつかの行をまとめてバッチ処理できます。Task

public void ReadData()
{
  var taskList = new List<Task<SomeResultType>>();

  var command = new SqlCommand()
  {
    CommandText = "SELECT * FROM Table";
    Connection = new SqlConnection("InsertConnectionString");
  };
  using(var reader = command.ExecuteReader())
  {
    var valueList = new List<object[]>(100);
    while(reader.Read())
    {
      var values = new object[reader.FieldCount];
      reader.GetValues(values);

      valueList.Add(values);

      if(valueList.Count == 100)
      {
        var localValueList = valueList.ToList();
        valueList.Clear();

        taskList.Add(Task<SomeResultType>.Factory.StartNew(() => Process(localValueList));
      }
    }
    if(valueList.Count > 0)
      taskList.Add(Task<SomeResultType>.Factory.StartNew(() => Process(valueList));
  }

  // this line completes when all tasks are done
  Task.WaitAll(taskList.ToArray());
}

public SomeResultType Process(List<object[]> valueList)
{
  foreach(var vals in valueList)
  {
    // put your processing code here, be sure to synchronize your actions properly
  }  
}
  • バッチサイズ(現在は100)は、実行されている実際の処理によって異なり、調整が必要な場合があります。
  • 同期にはそれ自体の課題があります。共有リソースについては十分に注意する必要があります。
于 2012-03-11T01:54:49.757 に答える
0

デュアルコアマシンを使用した並列ループをお勧めします。また、汎用リストを使用して各ループに使用してみてください。これにより、プロセスが高速化される可能性があります。

于 2012-03-11T01:55:07.560 に答える