在并行处理期间维护DataTable行的顺序

时间:2015-07-03 09:06:56

标签: c# parallel-processing task-parallel-library parallel.foreach

以下是当前的一段代码:

 Parallel.ForEach(dataTable.AsEnumerable(),row => {

     // Code to process the data row to Dictionary<object,object>
     // Unique Column name is the Dictionary Key
     // ConcurrentDictionary is used for thread safety      
     });

这里我使用Parallel.ForEach处理DataTable的行到类型Dictionary<object,object>的对象,最终结果是类型List<Dictionary<object,object>>,使用中间线程安全结构实现ConcurrentQueue<Dictionary<object,object>>DataTable的来源按给定顺序对数据进行排序,但在并行处理过程中总是会丢失。由于订单很重要,所以我提出了以下解决方法:

Parallel.For(0,RowCount,index => {

  int rowIndex = index;

  // Access the rows using the Index
  // Final structure will be of type ConcurrentDictionary<Custom>, 
  // with the RowIndex assigned based on original index
});

Class Custom
{
  public int RowIndex { get; set; }

  public Dictionary<object,object> DataDictionary {get; set;}
}

使用以下代码处理类型ConcurrentQueue<Dictionary<Custom>> customObj的最终结果:

customObj.OrderBy(x=>x.RowIndex).Select(y=>y.DataDictionary).ToList()

以下是我的问题:

  1. 有没有更好的方法来实现相同的并行处理,我可以保持原始订单,这是最重要的业务需求

  2. 在最终解决方案中,我需要局部变量rowIndex,我的理解是index是并行循环的一部分,不会导致关闭问题

  3. 任何指针?

3 个答案:

答案 0 :(得分:2)

您可以将PLINQParallelEnumerable.AsOrdered扩展程序

一起使用
  

启用对数据源的处理,就像它被排序一样,覆盖默认的无序。

在您的示例中,您可以通过以下方式使用它:

var result = dataTable.AsEnumerable().AsParallel().AsOrdered()
                      .Select(/*Process the row to dictionary*/).ToList();

答案 1 :(得分:1)

这个怎么样?

var items = new ConcurrentDictionary<DataRow, Dictionary<object,object>>;

Parallel.ForEach(dataTable.AsEnumerable(),row => {
    var result = ...; 
    items.Add(row, result);
});

var finalResult = dataTable.Rows.Cast<DataRow>().Select(r => items[r]).ToList());

答案 2 :(得分:0)

首先,您可以在Parallel.ForEach中获取Index而不是使用Parallel.For

Parallel.ForEach(dataTable.AsEnumerable(), (line, state, index) =>
{
    Console.WriteLine("{0} : {1}", index, line);
});

我可以看到,主要目的是避免使用OrderBy。 要实现这一点,请在ForLoop之前创建

var lines =  new YourClass[NumberOfElemnts] ;

在此之后,您可以使用您想要的任何循环填充此列表。让我们使用Parallel.For

Parallel.For(0, NumberOfElemnts, i =>
    {
        lines[i]=dataTable[i];
    });

根据@Panagiotis Kanavos的评论编辑它