James Michael Hare

...hare-brained ideas from the realm of software development...
posts - 136 , comments - 1095 , trackbacks - 0

My Links

News

Welcome to my blog! I'm a Sr. Software Development Engineer in Seattle, WA. I've been doing C++/C#/Java development for over 18 years, but have definitely learned that there is always more to learn!

All thoughts and opinions expressed in my blog and my comments are my own and do not represent the thoughts of my employer.

Blogs I Read

MCC Logo MVP Logo

Follow BlkRabbitCoder on Twitter

Tag Cloud

Archives

Post Categories

Thursday, December 20, 2012

C#/.NET Little Wonders: The Parallel.Invoke() Method

Once again, in this series of posts I look at the parts of the .NET Framework that may seem trivial, but can help improve your code by making it easier to write and maintain. The index of all my past little wonders posts can be found here.

Many times in software development, we want to invoke several processes at one time and continue when we get all the results back.  Obviously, if we were needing to process a sequence of items in a similar matter, we could use PLINQ.  Unfortunately, when the things we want to invoke asynchronously are heterogeneous tasks, PLINQ doesn’t really fit the bill.  Today we will look at a handy method in the Parallel class that can help us accomplish this.

Invoking processes asynchronously

Let’s say we have three completely separate methods and we want to invoke all three of them and the continue when they have returned.  These methods may be from separate classes and have completely different parameters and/or return types.  Thus, it may not be possible to use facilities like Parallel.ForEach() or PLINQ.

So how would we do this?  Well, we could obviously create three threads, start them, and join on them to come back:

   1: var threads = new List<Thread>
   2:                   {
   3:                       new Thread(SomeMethod),
   4:                       new Thread(() => SomeOtherMethod(x, y)),
   5:                       new Thread(() => { result = YetAnotherMethod(x, y, z); })
   6:                   };
   7: threads.ForEach(t => t.Start());
   8: threads.ForEach(t => t.Join());

Which, as you can see, can be used to call any method that fits Thread’s constructor (or can be adapted to it using a lambda, etc.). 

But that’s a bit heavy.  In addition, if an unhandled exception is thrown in one of those methods it will kill the thread, but we don’t have a very clean way of catching it here at the point of invocation.

Of course, we also have the Task class from the TPL which can help simplify threads:

   1: var tasks = new []
   2:                 {
   3:                     Task.Factory.StartNew(SomeMethod),
   4:                     Task.Factory.StartNew(() => SomeOtherMethod(x, y)),
   5:                     Task.Factory.StartNew(() => { result = YetAnotherMethod(x, y, z); })
   6:                 };
   7: Task.WaitAll(tasks);

This simplifies things on the surface, and better yet simplifies things a lot more with exception handling as well (TPL task exceptions get wrapped into a AggregateException and can be caught at the WaitAll() – and other possible places).

But there’s an even easier way…

Parallel.Invoke() – Easily invoke asynchronously

Just as the TPL gave us Parallel.For() and Parallel.ForEach() to make processing loops asynchronously a breeze, it also gave us Parallel.Invoke(), which takes any number of Action delegates and invokes them asynchronously and waits for them to rejoin.  If your methods have return values you want to store or need parameters, you can easily use lambda expressions as well:

   1: Parallel.Invoke(
   2:     SomeMethod,
   3:     () => SomeOtherMethod(x, y)),
   4:     () => { result = YetAnotherMethod(x, y, z); })

As long as the method can convert to an Action or you can form a lambda that will allow it to do so, you can use the Parallel.Invoke() to easily call them all in parallel without having to worry about starting or joining the threads or tasks.  And, because this is part of the TPL, you get the nice AggregateException handling as well that lets you easily catch tasks thrown from the underlying tasks.

Summary

When you just need to fire off several methods in parallel, consider the Parallel.Invoke().  It is a very handy way to invoke several different methods easily without having to worry about all the details of creating tasks or threads.

Posted On Thursday, December 20, 2012 8:50 PM | Comments (2) |

Powered by: