在 Parallel For 中使用共享变量

Using shared variable in Parallel For

我正在努力在下面的代码中使用 Parallel.For 而不是 for 循环。 由于 CoefficientVector 向量数组的大小相当大,因此对我来说只重置数组元素值而不是为每次迭代创建新的值是有意义的。

我尝试用Parallel For替换外层循环;并假设并行的每个分区,运行 通过一个单独的线程,将拥有它自己的 CoefficientVector class 副本,因此对我来说有意义(?)每个 CoefficientVector 对象实例线程并重置向量元素而不是重新创建数组。我虽然发现很难在 Parallel For 上进行这种优化(?)。有谁能帮忙吗

 static void Main(string[] args)
    {
        System.Diagnostics.Stopwatch timer = new System.Diagnostics.Stopwatch();
        timer.Start(); 

        int numIterations = 20000;
        int numCalpoints = 5000;
        int vecSize = 10000;

        CalcPoint[] calcpoints = new CalcPoint[numCalpoints];

        CoefficientVector coeff = new CoefficientVector();
        coeff.vectors = new Vector[vecSize];

        //not sure how to correctly use Parallel.For here
        //Parallel.For(0, numCalpoints, =>){
        for (int i = 0; i < numCalpoints;i++)
        {
            CalcPoint cp = calcpoints[i];

            //coeff.vectors = new Vector[vecSize];
            coeff.ResetVectors();

            //doing some operation on the matrix n times
            for (int n = 0; n < numIterations; n++)
            {
                coeff.vectors[n].x += n;
                coeff.vectors[n].y += n;
                coeff.vectors[n].z += n;
            }

            cp.result = coeff.GetResults();
        }

        Console.Write(timer.Elapsed);
        Console.Read();
    }
}

class CoefficientVector
{
    public Vector[] vectors;

    public void ResetVectors()
    {
        for (int i = 0; i < vectors.Length; i++)
        {
            vectors[i].x = vectors[i].y = vectors[i].z = 0;
        }
    }

    public double GetResults()
    {
        double result = 0;
        for (int i = 0; i < vectors.Length; i++)
        {
            result += vectors[i].x * vectors[i].y * vectors[i].z;
        }
        return result;
    }
}

struct Vector
{
    public double x;
    public double y;
    public double z;
}

struct CalcPoint
{
    public double result;
}

Parallel.For方法目前有12个overloads. Besides the variations of int, long, ParallelOptions and ParallelState action arguments you can notice several having additional generic argument TLocal like this:

public static ParallelLoopResult For<TLocal>(
    int fromInclusive,
    int toExclusive,
    Func<TLocal> localInit,
    Func<int, ParallelLoopState, TLocal, TLocal> body,
    Action<TLocal> localFinally
)

Executes a for loop with thread-local data in which iterations may run in parallel, and the state of the loop can be monitored and manipulated.

换句话说,TLocal 允许您分配、使用和释放一些线程本地状态,即正是您所需要的(TLocal 将是每个线程的 CoefficientVector 个实例).

因此您可以删除 coeff 局部变量并像这样使用上述重载:

CalcPoint[] calcpoints = new CalcPoint[numCalpoints];

Parallel.For(0, numCalpoints,
    () => new CoefficientVector { vectors = new Vector[vecSize] }, // localInit
    (i, loopState, coeff) => // body
    {
        coeff.ResetVectors();

        //doing some operation on the matrix
        for (int n = 0; n < coeff.vectors.Length; n++)
        {
            coeff.vectors[n].x += n;
            coeff.vectors[n].y += n;
            coeff.vectors[n].z += n;
        }

        calcpoints[i].result = coeff.GetResults();

        return coeff; // required by the body Func signature
    },
    coeff => { } // required by the overload, do nothing in this case
);