首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >多个Parallel.ForEach电话,MemoryBarrier?

多个Parallel.ForEach电话,MemoryBarrier?
EN

Stack Overflow用户
提问于 2015-05-15 03:19:22
回答 2查看 1.9K关注 0票数 5

我有一堆数据行,我想使用Parallel.ForEach来计算每一行的值,如下所示.

代码语言:javascript
复制
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启动之前对所有线程可见吗?

EN

回答 2

Stack Overflow用户

回答已采纳

发布于 2015-05-15 03:37:41

Parallel.ForEach()启动的工作将在返回之前完成。在内部,ForEach()为每个迭代生成一个Task,并对每个迭代调用Wait()。因此,您不需要同步ForEach()调用之间的访问。

对于具有ForEach()重载的单个任务,您确实需要记住这一点,这些任务允许您访问循环状态、聚合来自任务的结果等等。例如,在这个总结了1 ≤ x ≤ 100的简单示例中,传递给localFinally of Parallel.For()Action必须关注同步问题,

代码语言:javascript
复制
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

代码片段来源:Parallel Framework and avoiding false sharing

票数 5
EN

Stack Overflow用户

发布于 2015-05-15 03:54:36

由于多个线程将访问同一个变量"dr.B",因此需要确保C#代码是线程安全的。

尝试在每个操作https://msdn.microsoft.com/en-us/library/c5kehkcz.aspx周围使用“锁”

例如:

代码语言:javascript
复制
private Object thisLock1 = new Object();
...
lock(thisLock1)
{
    dr.C = 2.0 * dr.B;
}

...
lock(thisLock1)
{
    dr.B = 2.0*dr.A;
}

然而,这样做会使并行处理失败。因为每个线程都要等到下一个线程完成。

确保读取并行处理的潜在缺陷:https://msdn.microsoft.com/en-us/library/dd997403%28v=vs.110%29.aspx

票数 -1
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/30250980

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档