Thursday, December 6, 2012

C# Parallel Tasks (for)


Recently, I’ve been working on a project requiring the need to process very large quantities of data.  Many of the processes we have been writing can be broken up into parallel tasks.   While the .net framework has supported multithreading since the beginning, the 4.0 version introduced the System.Threading.Tasks namespace.    This is a nice collection of classes to help make multithreaded programming a bit easier.

Looking at the MSDN documentation

You will see a number of classes.  For this posting, I am going to zero-in on the Parallel class.

Here you will find heavily overloaded methods For and ForEach, both of these are methods to iteratively preform work on a thread.   If you have not looked at this before, it is a very welcome treat!

The first things you will add to your code are the using statements.
using System.Threading;           //  Thread
using System.Threading.Tasks;     // Parallel

The Parallel class is found in System.Threading.Tasks, but you may still want to use Thread, which will require System.Threading.

The basic syntax is this…
Parallel.For(Int32, Int32,Action<Int32>);
Argument 1, starting value (Inclusive)
Argument 2, ending value (Exclusive)
Argument 3, Action to perform

The premise is simple, you iterate just like you would a traditional for loop; however, unlike a traditional for loop, each iteration is performed in its own task (thread).   I'm demonstrating a Parallel.For loop, but there is also a Parallel.ForEach.

Here is a very simple example:

using System;
using System.Threading;
using System.Threading.Tasks;
namespace ParallelSample
{
    public class Program
    {
        public static void Main(string[] args)
        {
            Parallel.For(0, 10, DoThis);
            Console.Read();
        }
        public static void DoThis(int i)
        {
            //try adding a Thread.Sleep(5000);
            Console.WriteLine("*** {0} ThreadID= {1}", i,
Thread.CurrentThread.ManagedThreadId);
        }
    }
}

On the other hand, using lambda expressions, you might code something like this:

using System;
using System.Threading;
using System.Threading.Tasks;

namespace ParallelSample
{
    public class Program
    {
        public static void Main(string[] args)
        {
            Parallel.For(0, 10, i =>
            {
                Console.WriteLine("*** {0} ThreadID= {1}", i, Thread.CurrentThread.ManagedThreadId);
            });
            Console.Read();
        }
    }
}


This is but the very basics of the Parallel For.  The example simply demonstrates how to set your code up for multitasking iteration.  You will still need to follow the general rules for developing multithreaded programs and implement thread safe code where applicable.

One thing I did not mention was the use of the ParallelOptions object.   This object can provide some nifty features to your tasks, such a limiting the degrees of parallelism with the MaxDegreeOfParallelism property.  In the sample, below, I am using this object to limit only three threads of execution at a time.   This can help prevent overloading the server with worker threads.  Observe the overloaded For method.  It takes the ParallelOptions object as an arguement.  

        public static void Main(string[] args)
        {
            var po = new ParallelOptions() { MaxDegreeOfParallelism = 3 };

            Parallel.For(0, 10, po, i =>
                {
                    Console.WriteLine("*** {0} ThreadID= {1}", i,
                        Thread.CurrentThread.ManagedThreadId);
                });

            Console.Read();
        }


Lastly, you may want to take into consideration, the number of processors available.  One way to do this is to do the following:

Console.WriteLine(Environment.ProcessorCount);

When you run the examples, experiment and add additional code.  Perhaps try a Thread.Sleep call and observe the output.   








No comments:

Post a Comment