第一关:不要使用DataTable
运营这样的:
- 它的速度慢
- 它消耗太多内存
- ,你需要等待很长的时间,你可以真正开始之前处理数据
- 在此期间,额外的内核无所事事,因为将数据读入
DataTable
未被隔离。
- 同时在读取数据时,CPU通常几乎没有得到充分利用,因为网络或其他I/O延迟通常是主要因素。
如此反复:不要像这些操作使用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)取决于实际正在完成处理,可能需要进行调整。
- 同步拥有它自己的挑战,你必须非常小心地共享资源
好的解释但我有一些问题: 1-哪个更好,你建议的解决方案或者 做出多个任务,每个任务都使用SQLReader从数据库中读取一系列行(例如,基于寻呼),特别是在结果处理的情况下不是很重。 2-是否在任务BackgroundWork之间的性能有显着差异? – 2015-05-13 11:03:09