How to schedule Task on different thread priority?

2011/01/29

no comments

How to schedule Task on different thread priority?

 

Parallel, Task, Scheduler, Thread, Priority, C#, .net

.NET 4 brought as the Task Parallel Library (TPL)

which is great improvement over the old threading

techniques, both in terms of API and performance.

the TPL APIs is elegant and clear, but intentionally

the TPL team didn’t add API (out of the box) for scheduling

thread under different priorities.

 

this post deal discuss how to create custom TPL scheduler that schedule the

work units under different thread priorities.

 

the code sample for this post can be download from here.

 

TPL APIs

most of the TPL APIs expose overload with scheduler parameter.

out of the box TPL is having 2 schedulers:

  • Default scheduler.
  • synchronization context (Dispatcher) scheduler (for synchronizing work back into the
    synchronization context like UI thread), see TaskScheduler.FromCurrentSynchronizationContext().

 

How can we change the behavior of the scheduler?

building custom scheduler involve with inheritance of TaskScheduler.

in our sample we will use BlockingCollection<Task> for having

thread safe consumer producer pattern which will consume work

under custom thread that run on specific priority.

 

Overriding TaskScheduler

TaskScheduler is having small amount of virtual and abstract methods:

Code Snippet
  1. public class TaskScheduler
  2. {
  3.     public virtual int MaximumConcurrencyLevel { get; }
  4.     protected internal abstract void QueueTask(Task task);
  5.     protected internal virtual bool TryDequeue(Task task);
  6.     protected abstract bool TryExecuteTaskInline(Task task, bool taskWasPreviouslyQueued);
  7.     protected abstract IEnumerable<Task> GetScheduledTasks();
  8. }

the most important overrides is QueueTask which get

the task and responsible to schedule it execution.

in our implementation it enqueue the task into the producer consumer collection

and make sure that the worker threads is running.

Code Snippet
  1. protected override void QueueTask(Task task)
  2. {
  3.     _collection.Add (task);
  4.  
  5.     if (!_workerThread[0].IsValueCreated)
  6.     {
  7.         for (int i = 0; i < _maximumConcurrencyLevel; i++)
  8.         {
  9.             _workerThread[i].Value.Start();
  10.         }
  11.     }
  12. }

the actual task execution is done by consuming tasks (under the worker thread)

and call base.TryExecuteTask(task), as shown in the following code snippet:

Code Snippet
  1. foreach (Task task in _collection.GetConsumingEnumerable())
  2. {
  3.     base.TryExecuteTask(task);
  4. }

 

TPL APIs

the custom scheduler can be inject into the TPL APIs as shown in the following snippets:

Code Snippet
  1. Task.Factory.StartNew(…, cancelSouce.Token, TaskCreationOptions.None, scheduler);
  2. var options = new ParallelOptions { TaskScheduler = scheduler};
  3. Parallel.For(1, 10, options, i => …);

 

The sample

the sample compare execution of tasks with default and custom scheduler.

you may notice that thread that run under custom scheduler is also having thread name.

the output of the sample is look as follow:

Parallel, Task, Scheduler, Thread, Priority, C#, .net

Summary

the parallel team intentionally didn’t include priority scheduler for a good reason,

and most common execution should be avoid using such scheduler.

however there may be some special occasions which it might make sense

to use such scheduler, like:

  • execution of debug level logger write under low priority in order to prevent it from compete upon CPU resources.
  • execution test under controlled environment might take advantage of custom test scheduler.

the code sample for this post can be download from here.

 

kick it on DotNetKicks.com

Digg This
Add comment
facebook linkedin twitter email

Leave a Reply

Your email address will not be published. Required fields are marked *

You may use these HTML tags and attributes: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>