Custom Schedulers

[This documentation is for preview only, and is subject to change in later releases. Blank topics are included as placeholders.]

In rare scenarios, you might be able to achieve a performance speedup by creating a custom task scheduler based on the System.Threading.Tasks.TaskScheduler class. You can then specify this scheduler in client code by using the System.Threading.Tasks.ParallelOptions enumeration.

The following example demonstrates creating a custom task scheduler. This scheduler uses a single, dedicated thread to run all tasks queued to it.

//The following example demonstrates creating a custom task scheduler. This scheduler uses a single, dedicated thread to run all tasks queued to it.

Imports System
Imports System.Collections
Imports System.Collections.Generic
Imports System.Collections.Concurrent
Imports System.Linq
Imports System.Threading
Imports System.Threading.Tasks

Public NotInheritable Class DedicatedThreadTaskScheduler
    Inherits TaskScheduler
    Implements IDisposable

    Private _tasks As New BlockingCollection(Of Task)()
    Private _thread As Thread

    Public Sub New()
        _thread = New Thread(Sub()
                                 For Each Task In _tasks.GetConsumingEnumerable()
                                     Try
                                         TryExecuteTask(Task)
                                     Catch ex As InvalidOperationException
                                     End Try
                                 Next
                             End Sub)
        _thread.IsBackground = True
        _thread.Start()
    End Sub

    Protected Overrides Sub QueueTask(ByVal task As Task)
        _tasks.Add(task)
    End Sub

    Protected Overrides Function TryExecuteTaskInline(ByVal task As Task, ByVal taskWasPreviouslyQueued As Boolean) As Boolean
        If Thread.CurrentThread IsNot _thread Then Return False
        Return TryExecuteTask(task)
    End Function

    Public Overrides ReadOnly Property MaximumConcurrencyLevel() As Integer
        Get
            Return 1
        End Get
    End Property

    Protected Overrides Function GetScheduledTasks() As System.Collections.Generic.IEnumerable(Of Task)
        Return _tasks.ToArray()
    End Function

    ' Dispose is not thread-safe with other members.
    ' It may only be used when no more tasks will be queued
    ' to the scheduler.  This implementation will block
    ' until all previously queued tasks have completed.
    Public Sub Dispose() Implements IDisposable.Dispose
        If _thread IsNot Nothing Then
            _tasks.CompleteAdding()
            _thread.Join()
            _tasks.Dispose()
            _tasks = Nothing
            _thread = Nothing
        End If
    End Sub
End Class

using System;
using System.Collections;
using System.Collections.Generic;
using System.Collections.Concurrent;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;
// C#
public sealed class DedicatedThreadTaskScheduler : TaskScheduler, IDisposable
{
    private BlockingCollection<Task> _tasks = new BlockingCollection<Task>();
    private Thread _thread;
            
    public DedicatedThreadTaskScheduler()
    {
        _thread = new Thread(() =>
        {
            foreach (var task in _tasks.GetConsumingEnumerable())
            {
   TryExecuteTask(task);
            }
        });
        _thread.IsBackground = true;
        _thread.Start();
    }
            
    protected override void QueueTask(Task task)
    {
        _tasks.Add(task);
    }
            
    protected override bool TryExecuteTaskInline(Task task, bool taskWasPreviouslyQueued)
    {
        if (Thread.CurrentThread != _thread) return false;
        return TryExecuteTask(task);
    }
            
    public override int MaximumConcurrencyLevel { get { return 1; } }
            
    protected override IEnumerable<Task> GetScheduledTasks()
    {
        return _tasks.ToArray();
    }
            
    // Dispose is not thread-safe with other members.
    // It may only be used when no more tasks will be queued
    // to the scheduler.  This implementation will block
    // until all previously queued tasks have completed.
    public void Dispose() 
    {
        if (_thread != null)
        {
            _tasks.CompleteAdding();
            _thread.Join();
            _tasks.Dispose();
            _tasks = null;
            _thread = null;
        }
    }
}

See Also

Concepts

Task Parallel Library Overview