Search This Blog

Friday, May 6, 2011

.Net Framework 4.0 - Parallel Programing Pattern

In the .NET Framework 4, a slew of new support has been added to handle common needs in parallel programming, to help developers tackle the difficult problem that is programming for multi-core and manycore...


IMPLEMENTING A PARALLEL LOOPING CONSTRUCT => Parallelizing For Loop..
                         The .NET Framework 4 provides this in the form of the static Parallel class in the new System.Threading.Tasks namespace in mscorlib.dll. The Parallel class provides just three methods, each with several overloads. One of these methods is For, providing multiple signatures, one of which is almost identical
to the signature for MyParallelFor shown previously:
The following example shows you both sequential and parallel execution of a For loop.
      
SequentialProccessing()
{ 
    Camera camera = scene.Camera;
    for (int y = 0; y < screenHeight; y++)
    {
        int stride = y * screenWidth;
        for (int x = 0; x < screenWidth; x++)
        Patterns of Parallel Programming Page 15
        {
        Color color = TraceRay(
        new Ray(camera.Pos, GetPoint(x, y, camera)), scene, 0);
        rgb[x + stride] = color.ToInt32();
        }
    }
}

void RenderParallel(Scene scene, Int32[] rgb)
{
    Camera camera = scene.Camera;
    Parallel.For(0, screenHeight, y =>
    {
        int stride = y * screenWidth;
        for (int x = 0; x < screenWidth; x++)
        {
            Color color = TraceRay(
            new Ray(camera.Pos, GetPoint(x, y, camera)), scene, 0);
            rgb[x + stride] = color.ToInt32();
        }
    });
}

foreach (var student in students)
{
    student.GradePointAverage =
    student.Tests.Select(test => test.Grade * test.Weight).Sum();
}

To parallelize this, we take advantage of Parallel.ForEach:

Parallel.ForEach(students, student =>
{
    student.GradePointAverage =
    student.Tests.Select(test => test.Grade * test.Weight).Sum();
});
                               The return value ParallelLoopResult will give informations about each loop exeutions and also we can use AggregateExceptions to aggregate the exceptions happened each looping. Loopstate can be used to check weather a loop is in running state or in breaked and other loops can use the same for checking the status of other loops.


PARALLEL.INVOKE
               As shown previously, the Parallel class provides support for delightfully parallel loops through the Parallel.For and
Parallel.ForEach methods. Parallel also provides support for patterns based on parallelized regions of code, where every statement in a region may be executed concurrently.


Syntax : static void Invoke(params Action[] actions);


Parallel.Invoke(  () => ComputeMean(),
                  () => ComputeMedian(),
                  () => ComputeMode());



Here the above 3 methods will be executed in parallel.. 
Invoke will will execute methods asynchronously and wont wait for the methods to finish. Stillwe have options to wait for the delegates to wait . We can make use of the Task class for thisas below:

        static void Invoke(Action[] funs)
        {
            var tasks = (from function in funs
                         select Task.Factory.StartNew(function)).ToArray();            
Task.WaitAll(tasks);
        }
WaitAll will block untill all the tasks are finished...

Aggregation:                                 If the tasks that we executes in parallel  generates individual outputs, then the ultimate output will be the aggregation of all these outputs So here we have to consider how we can aggrgate the thread outputes toa  single output . Here we have 2 scenarios :
  1. Each thread will create output and collect and show the ouput( like in a list )
  2. A single output - which will be manipulated from the individual thread outputs. 

                       In the first case, to decrease these overheads and to minimize contention, the new thread-safe collections in the these collections reside in the System.Collections.Concurrent namespace, and are engineered to be scalable, minimizing the impact of contention. Some of these collections are implemented with lock-free techniques, while others are implemented using fine-grained locking. The following example shows the same:

       //Current way of collecting the output
        var output = new List<TOutput>(); 
        Parallel.ForEach(input, item => 
        { 
            var result = Compute(item); 
            lock (output) output.Add(result); 
        }); 

      
      //Using ConcurretnBag....
      var output = new ConcurrentBag<TOutput>(); 
      Parallel.ForEach(input, item => 
     { 
          var result = Compute(item); 

         output.Add(result); 
     }); 


PLINQ AGGREGATIONS - Like Linq, .Net4 introduces Plinq expressions as follows: 

var output = input.AsParallel() .Select(item => Compute(item)) .ToList();

In fact, not only does PLINQ handle all of the synchronization necessary to do this aggregation safely, it can also be used to automatically regain the ordering we lost in our parallelized version when using
Parallel.ForEach: 

var output = input.AsParallel().AsOrdered() .Select(item => Compute(item)) .ToList();
                   Single value Aggregations ( where we need a single output) can be obtained with Plinq as follows:

static double SerialLinqPi() 
{ 

    double step = 1.0 / (double)NUM_STEPS; 

    return Enumerable.Range(0, NUM_STEPS).Select(i => 

    { 

        double x = (i + 0.5) * step; 

        return 4.0 / (1.0 + x * x); 

    }).Sum() * step; 

} 

With a minimal modification, PLINQ can be used to parallelize this: 


static double ParallelLinqPi() 

{ 

    double step = 1.0 / (double)NUM_STEPS; 

    return ParallelEnumerable.Range(0, NUM_STEPS).Select(i => 

    { 

        double x = (i + 0.5) * step; 

        return 4.0 / (1.0 + x * x); 

    }).Sum() * step; 

}

No comments:

Post a Comment