Choosing Between the Task Parallel Library and the ThreadPool

Choosing Between the Task Parallel Library and the ThreadPool

  • Comments 6

If you’ve been following the development of the Task Parallel Library (TPL), or if you’re an avid reader of this blog, you’re likely aware that the default scheduler in TPL is based on the new and improved ThreadPool in .NET 4.  In light of this, though, quite a few folks have asked whether there are any advantages (particularly in regards to performance) to sticking with the existing ThreadPool APIs, e.g. QueueUserWorkItem.  This post attempts to briefly answer that question.

 

First, if your scenario requires the new functionality that Tasks provide, it’s best to use TPL.  Not only does this save you the time for rolling and optimizing your own solution, but TPL also has the advantage of being able to hook into internals of the ThreadPool that are not exposed publicly and that can boost performance in a variety of key scenarios.  For example, if you need to wait on your work items, Task.Wait (and its variants) benefits from tight integration with the ThreadPool’s work-stealing queues.  The story for other features like continuations and cancellation is similar.

 

Now, if your scenario does not require TPL’s features, such that your workloads are primarily fire-and-forget asynchronous work, then using QueueUserWorkItem may be appropriate.  Whether you want to do so, though, still depends on the specific workload.  On the one hand, as mentioned above, Tasks take advantage of the new work-stealing queues in the ThreadPool, which can help avoid issues of contention and cache coherency, both of which can lead to performance degradation.  On the other hand, additional functionality necessarily means additional overhead.  Using Tasks results in larger object allocations, and maintaining a Task’s lifecycle (status, cancellation requests, exception handling, etc.) requires extra work and synchronization.  As a result, there are surely some scenarios that will run faster using QueueUserWorkItem.

 

In conclusion, I’ll reiterate what the CLR team’s ThreadPool developer has already stated:

 

“Task is now the preferred way to queue work to the thread pool.”

 

In other words, we recommend that you start with TPL for all of your asynchronous needs.  Afterwards, if you suspect that your scenario would benefit from something more lightweight, it should be easy to try out QueueUserWorkItem.  If that works better, make the change – it won’t hurt our feelings =).

Leave a Comment
  • Please add 6 and 2 and type the answer here:
  • Post
  • What changes and additions are coming with Beta 2 of 10-4 *SHOW*? And (exactly) WHEN?

  • Hi,

    We're working on upcoming posts that will describe what's new in Beta 2.  Not sure exactly when.

    Danny

  • I have downloaded and playing with Beta-1 and Task Parallel Library. I seem to like the declarative approach. Task Scheduling, exception handling and cancellation is embedded in library quiet nicely.

    But I don't see any references to progress reporting and sending incremental results from the tasks. Its hard to believe that team would have forgot about these important things. Are they deliberately excluded from the framework?

    I raised a question on stackoverflow but no responses (and very low views) so far: http://stackoverflow.com/questions/1535749/support-of-progress-reporting-and-incremental-results-in-net-4-0-task-parallel

  • Hi Hemant,

    Re: progress reporting (to a UI control like a ProgressBar)

    This can be achieved using continuation Tasks that are scheduled to the UI thread.

    Re: sending incremental results

    Tasks are intended to be lightweight, usually producing only 1 significant result.  However, you can probably achieve this scenario with a concurrent collection.  For example, your Task could store intermediate results into a BlockingCollection<>, and consumers of that Task's work could read from the collection as results became available.

    Hope tihs helps,

    Danny

  • Thanks for the answer.

    About sending incremental results: Designing the tasks to be light weight and to produce small chunk of results is an important point. I will keep this in mind.

    About progress reporting: I am afraid I don't fully understand the statement "This can be achieved using continuation Tasks that are scheduled to the UI thread." I thought you create the task and launch it. How can you command it to run on **UI thread**? And by continuation tasks you mean two tasks running in parallel or one task scheduled to run after another (which doesn't make sense really because reporting the progress after task has finished is meaningless)

    Please can you give an example code snippet or point to an existing one on web? Some programmer said "One line of code speaks thousand words..."

    Thanks again for responding.

  • Hi Hemant,

    I thought I responded, but it doesn't seem to have posted.

    Re: scheduling Tasks to UI thread

    Here's an example:

    void Button1_Click(...)

    {

       var ui = TaskScheduler.FromCurrentSyncContext();

       Task.Factory.StartNew(() =>

       {

           // Do intense work on background threads.

       }).ContinueWith(_ =>

       {

           // Update a UI component.

       }, ui);

    }

    The FromCurrentSynchronizationContext method returns a TaskScheduler that delegates to the current synchronization context, captured at the time of the call.  If this is a Windows Forms or WPF app, the captured context will be the UI context, so Tasks scheduled to the 'ui' TaskScheduler will run on the UI thread.

    Re: reporting the progress after task has finished is meaningless

    Hm...I've actually often found reporting a finished Task's progress to be useful.  Of course it depends on the scenario.  If you want your Task to report intermediate progress, you could probably do it using a concurrent data structure.

    Hope this helps,

    Danny

Page 1 of 1 (6 items)