我有一堆数据行,我想使用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启动之前对所有线程可见吗?
发布于 2015-05-15 03:37:41
Parallel.ForEach()启动的工作将在返回之前完成。在内部,ForEach()为每个迭代生成一个Task,并对每个迭代调用Wait()。因此,您不需要同步ForEach()调用之间的访问。
对于具有ForEach()重载的单个任务,您确实需要记住这一点,这些任务允许您访问循环状态、聚合来自任务的结果等等。例如,在这个总结了1 ≤ x ≤ 100的简单示例中,传递给localFinally of Parallel.For()的Action必须关注同步问题,
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。
发布于 2015-05-15 03:54:36
由于多个线程将访问同一个变量"dr.B",因此需要确保C#代码是线程安全的。
尝试在每个操作https://msdn.microsoft.com/en-us/library/c5kehkcz.aspx周围使用“锁”
例如:
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
https://stackoverflow.com/questions/30250980
复制相似问题