Сначала: Не используйте DataTable
для таких операций :
- медленно
- слишком много памяти
- и вам нужно долго ждать, прежде чем вы сможете начать обработку данных
- В течение этого времени дополнительные ядра ничего не делают, поскольку чтение данных в
DataTable
не разбирается.
- Кроме того, при чтении данных ЦП обычно почти не используется, поскольку задержка ввода-вывода в сети часто является ведущим фактором.
Итак, еще раз: не используйте 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
}
}
Считыватель будет заблокирован во время выполнения вашего кода обработки, что означает, что больше строк не читается из БД.
Если код обработки тяжелый, возможно, стоит использовать библиотеку 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) зависит от фактической выполняемой обработки и, возможно, должен быть скорректирован.
- Синхронизация имеет свои собственные проблемы, вы должны быть очень осторожны с общими ресурсами