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;
}
}
}