-2

this is allmost my first attempt at parallel code, (first attempt worked fine and speeded up some code) but this below is causing strange issues and I cant see why. Both for loops below give the same result most of the time but not allways, i.e. res != res1. The function IdealGasEnthalpy is just calculating a number and not changing anything else, i cant figure out what the problem is or even where to begin to look, has anyone any suggestions?

        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];
        });

I tried the following code, but its very slow and doubled the execution time for the whole program compared to serial code.

       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;
                }
            });

Also tried this below, going to stick to non-parallel for this routine as the parallel versions are all a lot slower...

        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 Answers1

1

Your second operation needs to do an interlocked add, because += is not atomic. Remember this is shorthand for read the variable, add to it, and store the result. There is a race condition where two reads of the same old value could occur before either has stored the new result. You need to synchronize access.

Note that, depending on how computationally expensive your function is, interlocking with the Parallel.For approach might be slower than just doing a serial approach. It comes down to how much time is spent calculating the value versus how much time is spent synchronizing and doing the summation.

Alternately you could store the results in an array which you allocate in advance, then do the summation after all parallel operations are done. That way no two operations modify the same variable. The array trades memory for speed, since you eliminate overhead from synchronization.

PMV
  • 2,058
  • 1
  • 10
  • 15