3

我们想在我们的解决方案中围绕某些循环构建一个模式,这将允许它们根据因素串行或并行运行。下面是它的一般形式。

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

特别是围绕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 
});
4

1 回答 1

2

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

在开发 TPL 时,有一份非常出色的白皮书,说明了他们在开发 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 和 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
});
于 2012-04-16T12:55:50.010 回答