Dec 5, 2011

Parallel Programming

You can simply spin a new thread and assign some work

Thread t = new Thread(DoSomething);
 // Start the thread
 t.Start();
 // Request that oThread be stopped
 t.Abort();
 // Wait until oThread finishes. Join also has overloads
 // that take a millisecond interval or a TimeSpan object.
 t.Join();
 //This will throw ThreadStateException since aborted threads cannot be restarted
 oThread.Start();
 
The above approch is good for jobs which are going to be relatively long running

Issues
1. Spinning up a new thread and tearing one down are relatively costly actions, especially if compared to the cost of a small work being performed in the thread
2. Oversubscription is another issue. If too many threads are running, we’d have two components each fighting for the machine’s resources, forcing the operating system to spend more time context switching between components. Context switching is expensive for a variety of reasons, including the need to persist details of a thread’s execution prior to the operating system context switching out the thread and replacing it with another.

ThreadPool
.NET Framework maintains a pool of threads that service work items provided to it. The main method for doing this is the static QueueUserWorkItem

using (ManualResetEvent mre = new ManualResetEvent(false))
 {
  ThreadPool.QueueUserWorkItem(delegate{DoSomething();});
  ThreadPool.QueueUserWorkItem(delegate{DoSomethingelse();});
  ThreadPool.QueueUserWorkItem(delegate{DoSomeMore();});
  // Wait for all threads to complete.
  mre.WaitOne(1000000);
 }
 
1. So no overhead of thread creation and tear down.
2. Minimizes the possibility of oversubscription.
3. Once your machine is sufficiently busy, the threadpool will queue up requests rather than immediately spawn more threads.

Issues
1. There is a lim­ited num­ber of threads in the .Net Thread Pool (250 per CPU by default), and they are being used by many of the .Net frame­work classes (e.g. timer events are fired on thread pool threads) so you wouldn’t want your appli­ca­tion to hog the thread pool.
2. You cannot set the priority.

.Net 4.0
Parallel programming become much easier with the release of  .Net 4.0 System.Threading.Tasks.Parallel

ParallelLoopResult loopResult =
 Parallel.For(0, 100, (y,loopState) => 
 { 
  Console.WriteLine("This is " + y);
  //The other option is Break which gurantees that all the iterations till the breaking iterations are completed
  if(y > 20) loopState.Stop();
  if(loopState.IsStopped)
   Console.WriteLine("Loop was stopped while I am processing this");
 });
 Console.WriteLine("Ran to completion: " + loopResult.IsCompleted);


CancellationTokenSource cts = new CancellationTokenSource();
 var options = new ParallelOptions { CancellationToken = cts.Token };

 Task.Factory.StartNew(() =>
 {
  Thread.Sleep(3000);
  cts.Cancel();
 });

 try
 {
  Parallel.For(0, 10000, options, (y, loopState) =>
  {
   Thread.Sleep(1000);
   options.CancellationToken.ThrowIfCancellationRequested();
   Console.WriteLine("This is " + y);
  });
 }
 catch (OperationCanceledException e)
 {
  Console.WriteLine(e.Message);
 }


VERY SMALL LOOP BODIES

As previously mentioned, the Parallel class is implemented in a manner so as to provide for quality load balancing while incurring as little overhead as possible. There is still overhead, though. The overhead incurred by Parallel.For is largely centered around two costs:
1) Delegate invocations - Invoking a delegate incurs approximately the same amount of cost as a virtual method call.
2) Synchronization between threads for load balancing.

Task task1 = Task.Factory.StartNew(() => DoSomething(par1));
 Task task2 = Task.Factory.StartNew(() => DoSomething(par2));

 Task[] tasks = new Task[] {task1, task2};
 Task.WaitAll(tasks);

 Parallel.Invoke(
 () =>  DoSomething("1"),()=>DoSomething("1"));


Reference
http://www.microsoft.com/download/en/details.aspx?id=19222

No comments:

Post a Comment