Parallel.ForEach和IGrouping源项目问题
我正在尝试使用groupby语句在其中并行查询。查询类似于Parallel.ForEach和IGrouping源项目问题
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)
);
类型参数TSource
是元素类型,而不是集合类型。而第二个类型参数表示本地存储类型,所以它应该是List<T>
,如果你想要Add()
就可以了。这应该工作:
Parallel.ForEach<IGrouping<DateTime, object>, List<object>>
这是假设你实际上并没有object
在那儿,但某些特定的类型。
虽然在这里甚至不需要显式类型参数。编译器应该能够推断出它们。
但也有代码的其他问题:
你不应该从主要代表返回新
List
,但summary
处理该委托
finalResult
可能会在多个并发执行线程,所以你应该在那里使用锁或并发集合。
我要跳过“你确定你甚至需要优化这个”阶段,并假设你有你希望通过并行来解决性能问题。
首先,你没有试图用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%)
除此之外,你得到编译错误的原因是因为第一个类型参数应该是IGrouping<DateTime, object>
而不是IE<IG<..,..>>
。
列表不是线程安全的。改为使用['ConcurrentBag'](http://msdn.microsoft.com/en-us/library/dd381779.aspx)。 –