.net并行和串行循环

时间:2012-03-09 12:19:13

标签: c# multithreading parallel-extensions

我们希望在我们的解决方案中围绕某些循环构建一个模式,这将允许它们以串行或并行方式运行,具体取决于因素。以下是它的一般形式。

由于并发集合不与常规集合共享公共接口,因此我们需要某种适配器来编写通用代码。

特别是围绕循环体中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 
});

1 个答案:

答案 0 :(得分:2)

好奇为什么不在.NET 4.0中使用TPL? http://msdn.microsoft.com/en-us/library/dd537609.aspx

有一篇很好的白皮书说明了他们在开发TPL时所采取的考虑因素,如果你不能使用.NET 4,你应该看看论文并考虑其中的一些问题。

根据明确指出的评论更新了

我会使用一些语法糖,

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);
        }
    }
}

与您的实施相比,有两个主要优势。

  1. 您枚举两次,一次是将项目添加到循环中,另一次是在执行期间。
  2. 现在不是很明显,但是你要停止使用Parallel.ForEach,并使用最有效的吸气剂。 Parallel.ForeEach并不总是在IEnumerable中使用GetEnumerator。设计的枚举器不是并发的,如果你的项实现IList,Parallel.ForEach将使用索引器允许每个线程访问源中的元素,而无需等待枚举器迭代列表。 ConcurrentBag没有实现IList。
  3. 这是我提到的文件,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
    });