まず最初に:次のような操作には使用しないでください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)は、実行されている実際の処理によって異なり、調整が必要な場合があります。
- 同期にはそれ自体の課題があります。共有リソースについては十分に注意する必要があります。