Stephen Toub blogged that
Both SynchronizationContext and TaskScheduler are abstractions that represent a “scheduler”, something that you give some work to, and it determines when and where to run that work. There are many different forms of schedulers. For example, the ThreadPool is a scheduler: you call ThreadPool.QueueUserWorkItem to supply a delegate to run, that delegate gets queued, and one of the ThreadPool’s threads eventually picks up and runs that delegate. Your user interface also has a scheduler: the message pump.
So System.Reactive.Concurrency.EventLoopScheduler
, Dispatcher, ThreadPool, TaskScheduler, SyncrhonizationContext, and IScheduler implementations of Reactive Extensions are all "schedulers" in that sense.
What is the difference between them?
Why were they all necessary? I think I get EventLoop, Dispatcher, ThreadPool. IScheduler are also well explained.
But TaskScheduler and SyncrhonizationContext still not clear to me.
Stephen Cleary's excellent article explains SyncrhonizationContext, and I think I get it. Why then we needed TaskScheduler, is not clear.
Please explain or point to a source.
Each platform has it's own "scheduler" and they have their own abstractions around them. e.g. WinForms uses a message pump. WPF uses another message pump abstracted within "Dispatcher". A ThreadPool is another "scheduler" abstracted within "ThreadPool". These (and some others) are lower-level schedulers.
A Task and a TaskScheduler would like the user of a Task to not have to think about scheduling tasks at these lower levels (you can of course, in an abstracted way). You should be able to start a task and an ambient "scheduler" should take care of it. For example, TaskFactory.StartNew(()=>{LengthyOperation()})
should work regardless of what platform I'm running under. That's where a SynchronizationContext
comes in. It knows about what lower-level schedulers are involved in the currently running framework. That is passed along to a TaskScheduler
and that scheduler can both schedule tasks (possibly on to the ThreadPool) and schedule continuations through the lower-level scheduler associated with the currently running framework (see SynchronizationContext
) to maintain synchronization requirements. e.g. although you'd like your Task to run in the ThreadPool, you may want a continuation to run in the UI thread.
It's important to know that the TaskScheduler
is a abstraction of multiple other schedulers. This isn't the only reason it exists, but one of the reasons for this "extra" abstraction".