Specialized Task Schedulers in .NET 4 Parallel Extensions Extras
.NET 4 offers a default task scheduler for Task Parallel Library and PLINQ. This scheduler uses the improved .NET 4 pool of threads to queue and execute work for tasks and parallelized queries. It is also possible to create a custom scheduler for specific tasks or queries.
However, before doing so, you can consider the 13 customized task schedulers that are part of the most recent version of the Parallel Extensions Extras.
The System.Threading.Tasks.TaskScheduler class represents task schedulers. Its instance represents an object that handles the low-level work of queuing tasks onto threads. Remember that threads support the execution of the new tasks introduced by .NET Framework 4.
The default task scheduler provides an overall good performance and it is sufficient for most scenarios. By default, it considers tasks as short-lived units in order to efficiently support fine-grained parallelism scenarios. These are the most common scenarios for parallel tasks and parallelized queries. However, each task, i.e., an instance of System.Threading.Tasks.Task can also provide hints to help the default scheduler to take better decisions. For example, it is possible to specify that a task is going to be a long running one by specifying the TaskCreationOptions.LongRunning value to its CreationOptions. This value can be specified as a parameter for the Task constructor or the Task.Factory.StartNew method. When the default scheduler retrieves the value for the CreationOptions property and finds this flag, it will work with the task as a coarse-grained operation.
In a previous post, I introduced the Parallel Extensions Extras. These extras provide thirteen additional task schedulers, i.e., subclasses of System.Threading.Tasks.TaskScheduler. These customized schedulers are optimized for diverse scenarios. If you believe that some algorithms that use concurrent tasks would benefit from a specific scheduling mechanism, it is convenient to consider them before creating your own scheduler from scratch.
The TaskSchedulers folder within the ParallelExtensionExtras projects provides the following 13 classes:
- ConcurrentExclusiveInterleave.cs. The ConcurrentExclusiveTaskScheduler class provides a scheduler shim used to queue tasks to an interleave and execute these tasks on request of the interleave.
- CurrentThreadTaskScheduler.cs. The CurrentThreadTaskScheduler class provides a task scheduler that runs tasks on the current thread.
- IOCompletionPortTaskScheduler.cs. The IOCompletionPortTaskScheduler class offers a task scheduler that uses an I/O completion port in order to control concurrency. It is necessary to set the maximum number of threads in the scheduler to be executing concurrently and the number of threads to have available in the scheduler for executing tasks.
- IOTaskScheduler.cs. The IOTaskScheduler class provides a task scheduler that targets the I/O ThreadPool.
- LimitedConcurrencyLevelTaskScheduler.cs. The LimitedConcurrencyLevelTaskScheduler class offers a task scheduler that ensures a maximum concurrency level while running on top of the ThreadPool. It is necessary to set the maximum degree of parallelism desired for this scheduler.
- OrderedTaskScheduler.cs. The OrderedTaskScheduler class provides a task scheduler that ensures only one task is executing at a time. Tasks execute in the order that they were queued (FIFO). It is a subclass of LimitedConcurrencyLevelTaskScheduler that sends 1 as a parameter for its base class constructor.
- QueuedTaskScheduler.cs. The QueuedTaskScheduler class offers a task scheduler that provides control over fairness, priorities and the underlying threads used. It offers many constructors with diverse number of parameters that allow you to control the threads to create and use for processing work items.
- ReprioritizableTaskScheduler.cs. The ReprioritizableTaskScheduler class provides a task scheduler that supports changes in the priorities for previously queued tasks.
- RoundRobinTaskScheduler.cs. The RoundRobinTaskSchedulerQueue class offers a task scheduler that works with round-robin scheduling.
- StaTaskScheduler.cs. The StaTaskScheduler class provides a task scheduler that uses STA (short for Single-Threaded apartment) threads in order to support the execution of tasks. It is necessary to set the maximum number of threads desired for this scheduler.
- SynchronizationContextTaskScheduler.cs. The SynchronizationContextTaskScheduler class offers a task scheduler that targets a specific SynchronizationContext specified as a parameter in its constructor.
- ThreadPerTaskScheduler.cs. The ThreadPerTaskScheduler class provides a task scheduler that dedicates one thread per task.
- WorkStealingTaskScheduler.cs. The WorkStealingTaskScheduler class offers a work-stealing task scheduler. Its default parameters specify twice as many threads as there are processors to support the execution of tasks. However, it is also possible to specify the number of threads to use in the scheduler.
The following lines show a simple example of the creation of a new Task instance, t1, with a WorkStealingTaskScheduler instance, wsTaskScheduler, as its specific scheduler. The constructor for WorkStealingTaskScheduler receives the maximum number of threads to use for the scheduler as an optional parameter. In this case, the code defines the number of logical cores minus one as the maximum number of threads for this scheduler. If you create another Task instance and you don't specify wsTaskScheduler as the scheduler, it will use the default scheduler for the new task. If you want many tasks to use wsTaskScheduler, you have to specify it as a parameter to the Task.Factory.StartNew method.
var cts = new System.Threading.CancellationTokenSource(); var ct = cts.Token; var wsTaskScheduler = new System.Threading.Tasks.Schedulers.WorkStealingTaskScheduler (Environment.ProcessorCount - 1); var t1 = Task.Factory.StartNew( () => RunInATask(), ct, TaskCreationOptions.None, wsTaskScheduler);
Whenever you think that a specialized task scheduler is appropriate for your algorithm that involves parallelism in .NET 4, be sure to check the schedulers that can help you within Parallel Extension Extras. It is very simple to change the scheduler for a task to test the results. However, it is very important to test the results before using a customized scheduler.