多个Parallel.ForEach调用,MemoryBarrier?

问题描述 投票:0回答:2

我有一堆数据行,我想使用

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
,因为它还没有看到线程 42 的写入?
如果是这样,在 III 处插入内存屏障有帮助吗?这是否会强制在第二个 

double.NaN

开始之前,第一个

Parallel.ForEach
的更新对所有线程可见?
    

c# multithreading thread-safety task-parallel-library parallel.foreach
2个回答
5
投票
Parallel.ForEach

开始的工作将在其返回之前完成。在内部,

Parallel.ForEach()
为每次迭代生成一个
ForEach()
,并在每次迭代上调用
Task
。因此,您不需要在
Wait()
调用之间同步访问。

do

需要牢记对于具有ForEach()重载的各个任务,这些重载允许您访问循环状态、聚合任务结果等。例如,在这个总结了

ForEach()
的简单示例中,
1 ≤ x ≤ 100 
传递给
Action
localFinally
必须要关心同步问题,

Parallel.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()

片段源自:

并行框架和避免错误共享


-1
投票

尝试在每个操作中使用“锁定”

https://msdn.microsoft.com/en-us/library/c5kehkcz.aspx

例如

III

但是,这样做会破坏并行处理。因为每个线程都必须等待下一个线程完成。

确保了解并行处理的潜在陷阱:

https://msdn.microsoft.com/en-us/library/dd997403%28v=vs.110%29.aspx

© www.soinside.com 2019 - 2024. All rights reserved.