我正在尝试将查询与其中的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)
);
答案 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<..,..>>
。