.net并行和串行循环
本文关键字:循环 并行 net | 更新日期: 2023-09-27 18:27:26
我们希望围绕解决方案中的某些循环构建一个模式,允许它们根据因素以串行或并行方式运行。以下是它的一般形式。
由于并发集合与常规集合不共享一个公共接口,我们需要某种适配器来编写通用代码。
特别是关于循环体中addFunc
委托的使用,是否有任何东西会导致我们可能错过的长期问题?到目前为止运行良好,但是。。。。?
Action<SomeType> addFunc;
if(runInParallel)
{
addFunc = concurrentBag.Add;
loopDelegate = Parallel.ForEach;
}
else
{
addFunc = iList.Add;
loopDelegate = Serial.ForEach; // wrapper delegate for foreach
}
loopDelegate(source, item =>
{
SomeType result = longRunningTask(item);
...
addFunc(result); // will this
});
好奇为什么不在.NET 4.0中使用TPL?http://msdn.microsoft.com/en-us/library/dd537609.aspx
有一份很好的白皮书,介绍了他们在开发TPL时所考虑的问题,如果你不能使用.NET4,你应该看看这篇论文,并考虑其中的一些问题。
更新基于指出显而易见之处的评论。
我会用一些句法糖,比如
ForEach<Tsource>(Predicate<IEnumerable<TSource>> isParallel, IEnumerable<TSource> source, Action<TSource> body)
{
if(isParallel(source))
{
Parallel.ForEach<TSource>(source, body);
}
else
{
foreach (TSource element in source)
{
body(element);
}
}
}
与您的实现相比,有两个主要优势。
- 您枚举两次,一次是添加要循环的项,第二次是在执行期间
- 这并不明显,但您正在停止Parallel.ForEach和ForEach使用最有效的getter。Parallel.ForeEach不会总是在IEnumerable中使用GetEnumerator。枚举器在设计上是不并发的,如果您的项实现了IList,Parallel.ForEach将使用索引器允许每个线程访问源中的元素,而无需等待枚举器遍历列表。ConcurrentBag未实现IList
这是我提到的论文,顺便说一句,http://www.microsoft.com/download/en/details.aspx?displaylang=en&id=19222.
如果你在重复这篇文章,这是一本非常好的读物,但要特别注意,第1页[5-7]、第26页、第3页[0-2]。
句法糖意味着你可以像对待TPL、那样称呼它
MyParllelLibrary.ForEach( (list) => true, list), item =>
{
// What my code does
});