Components of Tasks & Threading in .NET

I recommend understanding the basics of async and await before you read this article. This is a good introduction from Stephen Cleary.

As you might know simply using async and await doesn't mean your code is executed on different threads. To achieve this you must use Task.Run, TaskFactory.StartNew or the Task Parallel Library.

This is an introduction in the different components at play when you want to schedule tasks on different threads.



TaskFactory

The TaskFactory is a simple container where you can configure options for the creation and continuation of Tasks. Furthermore you can specify an canncelation Token which will be used by all Tasks created through this factory. And lastly you can define your own TaskScheduler.

It's your choise if you want to use a TaskFactory to start a new task or if you want to start a task directly trough Task.Run.

MSDN TaskFactory

TaskScheduler

The TaskScheduler is responsible to run the next task on the correct thread. There are two implementations in the .NET Framework but you can easily create your own. The default TaskScheduler is the ThreadpoolTaskScheduler. And there is also the SynchronisationContextTaskScheduler which you can get by calling TaskScheduler.FromCurrentSynchronizationContext.

I will explain further details below.

MSDN TaskScheduler

ThreadPoolTaskScheduler, ThreadPool & Thread

This TaskScheduler uses the ThreadPool type to manage it's threads. It delegates the tasks to an thread it gets from the pool which isn't busy. The ThreadPool type is static meaning only one per process exists.
The thread pool provides new worker threads or I/O completion threads on demand until it reaches the minimum for each category. When a minimum is reached, the thread pool can create additional threads in that category or wait until some tasks complete. Beginning with the net_v40_short, the thread pool creates and destroys worker threads in order to optimize throughput, which is defined as the number of tasks that complete per unit of time. Too few threads might not make optimal use of available resources, whereas too many threads could increase resource contention.
Referencesource ThreadPoolTaskScheduler
MSDN ThreadPool
MSDN Thread

SynchronizationContextTaskScheduler & SynchronizationContext

The SynchronisationContextTaskScheduler is used internaly by the .net framework to delegate the work after the task to the origin thread. This means that you have a certain cpu overhead which you can/should avoid by calling ConfigureAwait(continueOnCapturedContext: false) on a task when it doesn't matter on which thread you return.

The SynchronizationContextTaskScheduler delegates the tasks to current SynchronizationContext. You can check which SynchronisationContext is set in your thread by calling SynchronizationContext.Current. You could also set the current context with the SynchronizationContext.SetSynchronizationContext method but I never needed to do that.

Threre are various different implementations of the SynchronizationContext the default type (SynchronizationContext) just delegates the tasks to the thread pool.

WindowsFormsSynchronisationContext and the Windows Message pump

The WindowsFormsSynchronisationContext uses the Invoke method of the Control type to redirect to the correct thread. The Invoke method just sends a windows message which then will be handled by the message pump of the ui thread.

(Windows Message pump) Work in progress
MSDN About Messages and Message Queues

DispatcherSynchronisationContext & Dispatcher

The DispatcherSynchronisationContext which is used in WPF uses the Dispatcher type to delegate the work to the threads. The description how the Dispatcher works is maybe coming later.

Work in progress

AspNetSynchronisationContext & LegacyAspNetSynchronizationContext

There is no synchronisation context in asp.net core as described here by Stephen Cleary.
Here you can read up on the Synchronisation context in asp.net.

Maybe there is coming more

Custom TaskScheduler example

This is a custom TaskScheduler which runs all tasks on one thread which uses the STA threading model.


Another example of an custom TaskScheduler is the LimitedConcurrencyLevelTaskScheduler provided by microsoft.
LimitedConcurrencyLevelTaskScheduler example by Microsoft

Task State Machine IL

Resources

...


This is work in progress and I really appreciate improvements, corrections and any other inputs about this post.

Comments

Popular posts from this blog

Creating a cordova plugin and using it with ionic

Debugging information and visual studio