Parallel.ForEach和IGrouping源项目问题

时间:2011-10-14 23:10:12

标签: c# linq .net-4.0 task-parallel-library

我正在尝试将查询与其中的groupby语句并行化。该查询类似于

    var colletionByWeek = (
                             from item in objectCollection
                             group item by item.WeekStartDate into weekGroups
                             select weekGroups
                          ).ToList();

如果我将Parallel.ForEach与下面的共享变量一起使用,它可以正常工作。但我不想在并行查询中使用共享变量。

var pSummary=new List<object>();
Parallel.ForEach(colletionByWeek, week =>
                                {
                                    pSummary.Add(new object()
                                    {
                                        p1 = week.First().someprop,
                                        p2= week.key,
                                        .....
                                    });
                                }
                 );  

因此,我已将上述并行语句更改为使用局部变量。但编译器抱怨源类型<IEnumerable<IGrouping<DateTime, object>>无法转换为System.Collections.Concurrent.OrderablePartitioner<IEnumerable<IGrouping<DateTime, object>>

我提供了错误的来源类型吗?或者这种类型的IGouping处理方式有何不同?任何帮助,将不胜感激。谢谢!

 Parallel.ForEach<IEnumerable<IGrouping<DateTime, object>>, IEnumerable<object>>
                        (spotColletionByWeek,
                         () => new List<object>(),
                         (week, loop, summary) =>
                         {
                             summary.Add(new object()
                             {
                                            p1 = week.First().someprop,
                                            p2= week.key,
                                            .....
                           });
                             return new List<object>();
                         },
                         (finalResult) => pSummary.AddRange(finalResult)
                        );

2 个答案:

答案 0 :(得分:2)

类型参数TSource是元素类型,而不是集合类型。第二个类型参数表示本地存储类型,因此如果您想要List<T>,则它应为Add()。这应该有效:

Parallel.ForEach<IGrouping<DateTime, object>, List<object>>

假设你实际上没有object,但有一些特定的类型。

虽然这里甚至不需要显式类型参数。编译器应该能够推断它们。

但代码中还有其他问题:

  • 您不应该从主代表返回新的List,而是summary

  • 处理finalResult的委托可能会在多个线程上并发执行,因此您应该在那里使用锁或并发集合。

答案 1 :(得分:1)

我将跳过'你确定你甚至需要优化这个'阶段,并假设你有一个性能问题,你希望通过并行化来解决。

首先,你没有尝试使用Parallel.Foreach<>来完成这项任务。我很确定使用PLINQ可以获得可读且更优的结果:

var random = new Random();
var weeks = new List<Week>();
for (int i=0; i<1000000; i++)
{
    weeks.Add(
      new Week {
          WeekStartDate = DateTime.Now.Date.AddDays(7 * random.Next(0, 100))
      });
}

var parallelCollectionByWeek =
    (from item in weeks.AsParallel()
     group item by item.WeekStartDate into weekGroups
     select new
     {
       p1 = weekGroups.First().WeekStartDate,
       p2 = weekGroups.Key,
     }).ToList();

值得注意的是,并行化GroupBy运算符会产生一些开销,因此效益最多也是微不足道的。 (一些粗略基准暗示加速10-20%)

除此之外,您收到编译错误的原因是因为第一个Type参数应该是IGrouping<DateTime, object>而不是IE<IG<..,..>>