并行代码导致奇怪的结果

时间:2016-11-16 17:13:36

标签: c# parallel-processing

这是我第一次尝试并行代码,(第一次尝试工作正常并加速了一些代码)但是这下面引起了一些奇怪的问题,我不明白为什么。下面的两个for循环在大多数时间给出相同的结果但不是总是,即res!= res1。功能IdealGasEnthalpy只是计算一个数字,而不是改变其他任何东西,我无法弄清楚问题是什么,甚至在哪里开始看,有没有人提出任何建议?

        double res = 0;
        object lockObject = new object();

        for (int I = 0; I < cc.Count; I++)
        {
            res += IdealGasEnthalpy(T, cc[I], enumMassOrMolar.Molar) * x[I];
        }

        double res1 = 0;

        Parallel.For(0, cc.Count, I =>
        {
            res1 += IdealGasEnthalpy(T, cc[I], enumMassOrMolar.Molar) * x[I];
        });

我尝试了以下代码,但与串行代码相比,它的速度非常慢,整个程序的执行时间加倍。

       double res = 0.0d;

        Parallel.For(0, cc.Count,
            () => 0.0d,

            (x, loopState, partialResult) =>
            {
                return partialResult += IdealGasEnthalpy(T, cc[x], enumMassOrMolar.Molar) * X[x];
            },

            (localPartialSum) =>
            {
                lock (lockObject)
                {
                    res += localPartialSum;
                }
            });

还尝试了下面这个,因为并行版本的速度都慢了很多,所以这个例程会坚持非并行...

        double res = 0.0d;
        double[] partialresult = new double[cc.Count];

        Parallel.For(0, cc.Count, i =>
            {
                partialresult[i] = IdealGasEnthalpy(T, cc[i], enumMassOrMolar.Molar) * X[i];
            });

        for (int i = 0; i < cc.Count; i++)
        {
            res += partialresult[i];
        }*

1 个答案:

答案 0 :(得分:1)

你的第二个操作需要进行互锁添加,因为+ =不是原子的。请记住,这是读取变量,添加变量和存储结果的简写。存在竞争条件,在存储新结果之前可能发生两次相同旧值的读取。您需要同步访问权限。

请注意,根据您的函数的计算成本如何,与Parallel.For方法的联锁可能比仅执行串行方法更慢。归结为计算价值所花费的时间与同步和总结所花费的时间有关。

或者,您可以将结果存储在预先分配的数组中,然后在完成所有并行操作后进行求和。这样,没有两个操作修改同一个变量。由于您可以消除同步开销,因此该阵列可以交换内存以提高速度。