Combining Tasks Using WhenAll

Tags: TPL, ASP.NET, C#

If you want to combine one or more Tasks into one Task and wait for all of them to complete you can use a ASP.NET 4.5 feature called WhenAll.  WhenAll takes a collection of tasks and returns one task that represents all the work done by all of the individual tasks.  

  • If any of the tasks throw an error, IsFaulted will be true.
  • When all the tasks complete, IsCompleted will be true.

Let's Look at an Example

static void Main(string[] args)
{
	Console.WriteLine("Begin...");
	TPLClass tPLClass = new TPLClass();
	Task task1 = Task.Run(() => tPLClass.SlowMethod(1));
	//Task task2 = Task.Run(() => tPLClass.SlowMethodThatErrors(2));
	Task task2 = Task.Run(() => tPLClass.SlowerMethod(2));
	Task<int[]> tasks = Task.WhenAll(task1, task2);
	tasks.ContinueWith(t =>
	{
		Console.WriteLine("Continuing...");
		if (t.IsFaulted)
		{
			// if one or more errors occur, an AggregateException is returned
			Console.WriteLine("Exception Count: " + t.Exception.InnerExceptions.Count);
			Console.WriteLine("Exception Message: " + t.Exception.InnerException.Message);
		}
		if (t.IsCompleted)
		{
			// if successful, an Array of int is returned
			foreach (var item in t.Result)
			{
				Console.WriteLine(item);
			}
		}
	});

	Console.ReadKey();
		
}

So here we have two tasks for two different method calls, SlowMethod and SlowerMethod.   Each takes an int, sleeps, and returns an int.  I use WhenAll to combine the two tasks into one.  I use ContinueWith to run the tasks asynchronously.  The ContinueWith takes a func which it will execute when the tasks of the WhenAll complete.  Inside the ContinueWith the func writes out the results of the tasks which will be in the form of an integer array.  The output looks like:

Begin... appears first then after the tasks complete, the rest of the output shows up.

If a Task Throws an Exception

Now if I change the above code to uncomment the method that errors and comment out SlowerMethod like so, 

Task task2 = Task.Run(() => tPLClass.SlowMethodThatErrors(2));
//Task<int> task2 = Task.Run(() => tPLClass.SlowerMethod(2));

one of the tasks in the WhenAll will error and it will be in a faulted state. The ContinueWith will then process the AggregateException.  The AggregateException wraps the inner exceptions.  So in my example code, the ContinueWith will write the number of exceptions in the InnerExceptions collection (there will only be one in this case) and write the error message.   In this case the output looks like:

 

As before, Begin... appears first then after the tasks complete or error, the rest of the output shows up.

Isn't this awesome?  So much cleaner and easier than the old ways of messing with the thread pool or using events.  

More Info

WhenAll

ContinueWith

No Comments

Add a Comment