Saturday, August 31, 2013

How Parallel.ForEach Handles Exceptions

Think quick, what does this output:

var ints = Enumerable.Range(0, 99);
try
{
    Parallel.ForEach(ints, i =>
    {
        throw new Exception("Exception #" + i);
    });
}
catch (AggregateException ex)
{
    Console.WriteLine("Caught " + ex.Flatten().InnerExceptions.Count + " exceptions");

}

The Task Parallel Library's Parallel.ForEach statement can make things easier, but it may not always work the way you expect.

If you said either "Caught 100 exceptions" or "Caught 1 exceptions" you're wrong.

How Stuff Works

This one threw me recently (pardon the pun) and I had to look it up.  At first the documentation says:

Sometimes, two steps take place in the opposite order than they would if the loop were sequential. The only guarantee is that all of the loop's iterations will have run by the time the loop finishes.

Which might lead you to think it would execute all 100 iterations before throwing the Aggregate exception.  But that's a lie, because later it says:

If the body of a parallel loop throws an unhandled exception, the parallel loop no longer begins any new steps. By default, iterations that are executing at the time of the exception, other than the iteration that threw the exception, will complete. After they finish, the parallel loop will throw an exception in the context of the thread that invoked it.

In other words Parallel.ForEach takes the items you're enumerating, breaks them up into groups (whose size is based on the MaxDegreeOfParallelism property and the number of cores on your machine) and then simultaneously executes the lambda expression on all of the items in the first group, then all the items in the second group, etc.

If an exception occurs while processing of one of the items in a group then Parallel.ForEach will continue executing all of the items in the current group, but it will not execute any subsequent groups.

So what does the code above output?  The answer is "Caught [group size] exceptions".  On my machine with 8 logical processor that number happens to be 9.

Don't Stop Now

If you want to execute all iterations, regardless of exceptions, to ensure that as many side effects happen as possible while handling exceptions later en-mass you could try:

ints.AsParallel().ForAll(i => { DoStuff(i); });

But you'll quickly discover it has the same problem.  What you're probably looking for is something like Task.WaitAll:

var tasks = ints.Select(i => new TaskFactory().StartNew(() => DoStuff(i)));
Task.WaitAll(tasks.ToArray());

The above works by mapping your input array into a list of tasks via a .Select() statement.  Then, by default, Task.WaitAll will block until all tasks have run to completion, regardless of whether there was an exceptional state or not.

Conclusion

Exception handling and threading are some of the trickiest topics to master.  Hopefully, like me as of today, you're now slightly better prepared for writing more robust multi-threaded applications.

Thursday, August 15, 2013

Distributing SCRUM Planning Poker via Google Docs

Ever had to do planning poker with remote team-members?

via Scrum Shortcuts


Wait, not that remote.  As in, another time zone kind of remote.

Planning poker cards obviously don't work unless you've got a nice video conference setup.  Going person-by-person isn't terrible, but it removes one of the biggest benefits of pointing.

Why Must Everyone Reveal Simultaneously Anyway?


Revealing points simultaneously levels the playing field.  It provides an unbiased insight into what every team member is thinking.  More than that it forces everyone to actively think about the problem from their own perspective without yielding to louder, more experienced, or more domain knowledgeable team members.  This problem can be compounded when a team is distributed.

A simultaneous reveal says we care about every perspective on the team no matter how inexperienced, introverted, or physically far away a person is.

Distributed, Free, Simultaneous Reveals


I really love the collaborative features of Google Docs.  If you haven't tried them yet, you will too.  What you may not have considered is how nicely it works for a SCRUM planning sessions:



In the screenshot we've got a spreadsheet with some conditional formatting to quickly show how far off everyone's estimates are.  We've got a place to chat and a place where anyone can quickly throw up and collaborate on the new user stories that always result from planning sessions.  Someone can go back later and move those into the official repository.

But more importantly for simultaneous reveals, the points aren't sent across the wire until team members hit enter.  In other words the current user in the screenshot has an estimate in A2 that isn't visible to everyone.  Instead it appears to everyone else gray, just like B2.  Once everyone's cell has turned gray someone counts to three over the phone, everyone hits enter, values become visible, the conditional formatting kicks in, and if the estimates are off enough, then discussion ensues.

It works so well I'm half tempted to use it on my next project even if team members aren't distributed. Incidentally I can't take credit for this idea.  The original idea came from Jeff Kunkle and we refined it as a team into what you see above.

Summary


Having remote team members can be challenging.  Hopefully the technique described here can make distributed development just a little easier.  Feel free to post in the comments on what techniques you use to help with distributed development.