Using a shared variable in Parallel For
I am struggling to use Parallel.For in the code below instead of a loop. Since the size of the vector array CoefficientVector is quite large, it only makes sense to me to reset the value of the array elements instead of creating it for each iteration.
I am trying to replace the outer loop with Parallel For; and assuming that each parallel section for being executed by a separate thread will have its own copy of the CoefficientVector class, so it makes sense (?) for me to have one instance of the CoefficientVector object for each thread, and reset the vector elements rather than re-creating the array. Though I am having a hard time doing this optimization (?) In Parallel For. Can anyone help.
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;
}
source to share
Parallel.For
has 12 overloads . In addition to variations in the arguments int
, long
, ParallelOptions
and ParallelState
you may notice some additional arguments TLocal
, such as the 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 can be performed in parallel and the state of the loop can be monitored and manipulated.
In other words, TLocal
it allows you to allocate, use, and free some thread-local state, which is exactly what you need ( TLocal
will be your CoefficientVector
thread instance ).
So, you can remove the local variable coeff
and use the above overload like this:
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
);
source to share