1

使用并行扩展时是否需要关注 MemoryBarriers?

编辑 - 详细说明原始问题是开放式的:(@xanatos 的答案是我正在寻找的答案)

举一个具体的例子:假设我使用 Parallel.ForEach 并且每次迭代都设置类中属性的值(每次迭代都设置它自己的特定属性,没有两次迭代设置相同属性的值)。在调用 Parallel.ForEach 的同一线程上,我访问从 Parallel.ForEach 设置的属性。

class Program
{
  static void Main(string[] args)
  {
    var t = new Test();
    t.InitializePropertiesInParallel();
    var a = t.PropA; // Could never be 0?
    var b = t.PropB; // Could never be 0?
  }
}

public class Test
{
  public int PropA { get; set; }
  public int PropB { get; set; }

  public void InitializePropertiesInParallel()
  {
    var initializers = new List<Action<int>>()
    {
      i => PropA = i,
      i => PropB = i
    };

    initializers.AsParallel().ForAll(a => a(1));
  }
}
4

2 回答 2

2

请记住一件事:缓存行失效。这是一个复杂的话题,但这里有一篇很棒的 MSDN 文章

在这个特定示例中,它的要点是,因为您正在从两个不同的线程修改同一个对象实例,即使您没有触及内存中完全相同的位置,您也将触及同一个缓存行,所以当处理器 1 上的第一个线程更改内存,缓存将在处理器 2 再次读取/写入之前被刷新和更新。

也就是说,再次考虑您仅使用两个道具的具体示例,这是一个微优化,绝对不用担心。如果您要对其进行推断,则需要注意一些事情。

于 2012-03-15T07:13:21.213 回答
1

如果每个工人都不需要其他工人准备的数据(因此不存在工人 1 写入 A 而工人 2 读取 A 的情况),则不需要MemoryBarrier. 当所有任务完成时,有一个Wait充当 a MemoryBarrier(最后,即使你没有看到它,在某处有一个同步构造等待所有工作人员完成)

于 2012-03-13T17:29:45.407 回答