Parallelism in .NET – Part 16, Creating Tasks via a TaskFactory

The Task class in the Task Parallel Library supplies a large set of features.  However, when creating the task, and assigning it to a TaskScheduler, and starting the Task, there are quite a few steps involved.  This gets even more cumbersome when multiple tasks are involved.  Each task must be constructed, duplicating any options required, then started individually, potentially on a specific scheduler.  At first glance, this makes the new Task class seem like more work than ThreadPool.QueueUserWorkItem in .NET 3.5.

In order to simplify this process, and make Tasks simple to use in simple cases, without sacrificing their power and flexibility, the Task Parallel Library added a new class: TaskFactory.

The TaskFactory class is intended to “Provide support for creating and scheduling Task objects.”  Its entire purpose is to simplify development when working with Task instances.  The Task class provides access to the default TaskFactory via the Task.Factory static property.  By default, TaskFactory uses the default TaskScheduler to schedule tasks on a ThreadPool thread.  By using Task.Factory, we can automatically create and start a task in a single “fire and forget” manner, similar to how we did with ThreadPool.QueueUserWorkItem:

Task.Factory.StartNew(() => this.ExecuteBackgroundWork(myData) );

This provides us with the same level of simplicity we had with ThreadPool.QueueUserWorkItem, but even more power.  For example, we can now easily wait on the task:

// Start our task on a background thread
var task = Task.Factory.StartNew(() => this.ExecuteBackgroundWork(myData) );

// Do other work on the main thread, 
// while the task above executes in the background
this.ExecuteWorkSynchronously();

// Wait for the background task to finish
task.Wait();

TaskFactory simplifies creation and startup of simple background tasks dramatically.

In addition to using the default TaskFactory, it’s often useful to construct a custom TaskFactory.  The TaskFactory class includes an entire set of constructors which allow you to specify the default configuration for every Task instance created by that factory. 

This is particularly useful when using a custom TaskScheduler.  For example, look at the sample code for starting a task on the UI thread in Part 15:

// Given the following, constructed on the UI thread
// TaskScheduler uiScheduler = TaskScheduler.FromCurrentSynchronizationContext();

// When inside a background task, we can do
string status = GetUpdatedStatus();

(new Task(() =>
    {
        statusLabel.Text = status;
    }))
.Start(uiScheduler);

This is actually quite a bit more complicated than necessary.  When we create the uiScheduler instance, we can use that to construct a TaskFactory that will automatically schedule tasks on the UI thread.  To do that, we’d create the following on our main thread, prior to constructing our background tasks:

// Construct a task scheduler from the current SynchronizationContext (UI thread)
var uiScheduler = TaskScheduler.FromCurrentSynchronizationContext();
// Construct a new TaskFactory using our UI scheduler
var uiTaskFactory = new TaskFactory(uiScheduler);

If we do this, when we’re on a background thread, we can use this new TaskFactory to marshal a Task back onto the UI thread.  Our previous code simplifies to:

// When inside a background task, we can do
string status = GetUpdatedStatus();

// Update our UI
uiTaskFactory.StartNew( () => statusLabel.Text = status);

Notice how much simpler this becomes!  By taking advantage of the convenience provided by a custom TaskFactory, we can now marshal to set data on the UI thread in a single, clear line of code!

About Reed
Reed Copsey, Jr. - http://www.reedcopsey.com - http://twitter.com/ReedCopsey

Comments

5 Responses to “Parallelism in .NET – Part 16, Creating Tasks via a TaskFactory”
  1. Highlander4 says:

    Thanks for this post. I was grinding my brains all day long on the usage of a task with the uiScheduler and you saved my day. The syntax is very temperamental and I just couldn’t get it right until I saw your post.

    Thanks again.

  2. Excellent post!

    I was banging my head trying to get the UI to update correctly from the background thread. You saved the day!

Trackbacks

Check out what others are saying about this post...
  1. [...] This post was mentioned on Twitter by Caspar Kleijne, Reed Copsey, Jr.. Reed Copsey, Jr. said: Blog series on Parallelism in .NET. Published Part 16, Creating Tasks via a TaskFactory http://bit.ly/b22P6I #csharp #dotnet #TPL [...]

  2. Interessante post sull…

    Interessante post sull…

  3. [...] Thanks to ReedCopsey, Jr. I found that on his website, and it was very [...]



Speak Your Mind

Tell us what you're thinking...
and oh, if you want a pic to show with your comment, go get a gravatar!