我正在开发一个应用程序,它需要使用存储过程从sql server db获取源数据,进行一些计算并使用另一个存储过程将结果存储回sql server。总的源数据大约是10.000.000条记录,可以在100个不同的数据集中分开。所以在我能够使用迭代数据引导程序完成整个过程顺序(花了50多个小时)后,我现在正在寻找一个平行化过程的解决方案,这样我就可以同时运行8个计算(我使用的服务器有2个四核CPU的)。 我尝试了EF6的例子,但最终出现问题,因为EF不是线程安全的。即使是每个上下文被隔离的解决方案都不起作用。通过利用
using (var ctx = new MyEntities())
{
var resGuid = ReserveGroupId(pIdForCalc, ctx);
int pageNumber = 0;
int pageSize = 200;
bool DataNotComplete = true;
while (DataNotComplete)
{
List<GetNextCalcDataSetPaged_Result> lstCalcDataSet = GetDataPaged ((pIdForCalc,pageNumber,pageSize,ctx);
if (lstCalcDataSet != null)
{
DataNotComplete = lstCalcDataSet.Count == pageSize;
Parallel.ForEach(lstCalcDataSet, CalcDataRecord =>
{ if (ctx != null) CalcBundelSetParallel(CalcDataRecord, ctx); });
}
pageNumber++;
}
答案 0 :(得分:0)
一种肮脏的方式是使用填充了断开数据块的断开连接的DataSet,例如,每次200,000条记录。进入内存后,您可以像这样并行处理它
//Setup empty dataset for results setting its schema
dsResultSet.Tables.Add(ORM.GetDataSet("MyDataToProcess").Tables[0].Clone());
object key = new object();
//Iterate in parallel your Dataset
Parallel.ForEach(ORM.GetDataSet("MyDataToProcess").Tables[0].AsEnumerable(), drow =>
{
if (((string)drow["DataRecordKey"]).Contains(SomeKey))
{
//some process with the record
//...
lock (key)
{
//Add the result to other disconnected DataSet
dsResultSet.Tables[0].BeginLoadData();
dsResultSet.Tables[0].Rows.Add(drow.ItemArray);
dsResultSet.Tables[0].EndLoadData();
}
}
});`
我知道,它不像Entity Framework代码,但是这段代码对我有用,可以在内存中的200,000条记录上达到毫秒级操作。结果的第二个表的原因是DataTables不是线程安全的更新,只是为了读取。