并行迭代多个大型数据集

时间:2013-12-02 13:06:06

标签: c# sql-server ado.net

我正在开发一个应用程序,它需要使用存储过程从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++;
}

1 个答案:

答案 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不是线程安全的更新,只是为了读取。