Mic*_*lli 5 c# multithreading task-parallel-library parallel.foreach
我有一堆数据行,我想使用Parallel.ForEach来计算每一行的某些值,就像这样......
class DataRow
{
    public double A { get; internal set; }
    public double B { get; internal set; }
    public double C { get; internal set; }
    public DataRow()
    {
        A = double.NaN;
        B = double.NaN;
        C = double.NaN;
    }
}
class Program
{
    static void ParallelForEachToyExample()
    {
        var rnd = new Random();
        var df = new List<DataRow>();
        for (int i = 0; i < 10000000; i++)
        {
            var dr = new DataRow {A = rnd.NextDouble()};
            df.Add(dr);
        }
        // Ever Needed? (I)
        //Thread.MemoryBarrier();
        // Parallel For Each (II)
        Parallel.ForEach(df, dr =>
        {
            dr.B = 2.0*dr.A;
        });
        // Ever Needed? (III)
        //Thread.MemoryBarrier();
        // Parallel For Each 2 (IV)
        Parallel.ForEach(df, dr =>
        {
            dr.C = 2.0 * dr.B;
        });
    }
}
(在这个例子中,没有必要并行化,如果有的话,它可以全部进入一个Parallel.ForEach.但这应该是一些代码的简化版本,在这里设置它是有意义的).
是否有可能在这里重新排序读取,以便最终得到一个数据行,其中B!= 2A或C!= 2B?
假设第一个Parallel.ForEach(II)指定工作线程42处理数据行0.并且第二个Parallel.ForEach(IV)指定工作线程43处理数据行0(第一个Parallel.ForEach完成时) .是否有可能在线程43上读取第0行的dr.B返回double.NaN,因为它还没有看到来自线程42的写入?
如果是这样,在III处插入内存屏障是否有帮助?在第二个Parallel.ForEach启动之前,这是否会强制第一个Parallel.ForEach的更新对所有线程可见?
a 开始的工作Parallel.ForEach()将在它返回之前完成。在内部,为每次迭代ForEach()生成一个Task,并调用每个迭代Wait()。因此,您不需要在ForEach()调用之间同步访问。
对于具有重载的单个任务,您确实需要牢记这一点,这些任务ForEach()允许您访问循环状态、聚合任务的结果等。例如,在总结的这个简单示例中1 ? x ? 100,Action传递给localFinallyofParallel.For()必须关注同步问题,
var total = 0;
Parallel.For(0, 101, () => 0,  // <-- localInit
(i, state, localTotal) => { // <-- body
  localTotal += i;
  return localTotal;
}, localTotal => { <-- localFinally
  Interlocked.Add(ref total, localTotal); // Note the use of an `Interlocked` static method
});
// Work of previous `For()` call is guaranteed to be done here
Console.WriteLine(total);
在您的示例中,没有必要在ForEach()调用之间插入内存屏障。具体来说,循环IV可以取决于II完成的结果,并且Parallel.ForEach()已经III为您插入。
片段来源:并行框架和避免错误共享