1
Vote

Scheduler Façades

description

Related discussion:
http://social.msdn.microsoft.com/Forums/en-US/rx/thread/1be3a07f-68c2-42a0-b5f5-ec3446f9f514

Add new properties to the Scheduler class (examples provided below) to simplify the choice for users, to hide internal optimization details and to make the semantics of choosing a scheduler reflect the actual underlying concerns of operators.

Furthermore, consider making existing platform-specific schedulers' internal (at least their parameterless constructors) and removing the "Instance" and "Default" factories for them; Alternatively, consider changing the behavior of operators so that when they receive a concrete scheduler no optimizations are applied and the specified scheduler is used directly, and only apply optimizations when a façade scheduler is passed in, avoiding the need for the DisableOptimizations operator.

PROPOSAL FOR COMPLETE LIST OF FACADES AND SCHEDULER CLASSES

NOTE: The schedulers suggested below were given precedence based on implementations for .NET 4.5 only; however, the suggested abstractions would allow Rx to internally choose the best scheduler for the job by considering the current platform.

• Scheduler.Synchronous = ImmediateScheduler
• Scheduler.Asynchronous
With precedence from left to right:
Standard = DispatcherScheduler / ControlScheduler -> SynchronizationContextScheduler -> CurrentThreadScheduler
ISchedulerLongRunning = NewThreadScheduler
ISchedulerPeriodic = DispatcherScheduler / ControlScheduler -> ThreadPoolScheduler
• Scheduler.Concurrent
With precedence from left to right:
Standard = ThreadPoolScheduler
ISchedulerLongRunning = NewThreadScheduler
ISchedulerPeriodic = ThreadPoolScheduler
• ControlScheduler: Useful for when thread-affinity is required; e.g., Scheduler.Asynchronous may choose NewThreadScheduler, so users must be able to call .ObserveOn(ControlScheduler) explicitly at the end of a query if it must notify observers on the UI thread.
• CurrentThreadScheduler: Useful for simple applications and experimentation.
• DispatcherScheduler: Useful for when thread-affinity is required; e.g., Scheduler.Asynchronous may choose NewThreadScheduler, so users must be able to call .ObserveOnDispatcher() explicitly at the end of a query if it must notify observers on the UI thread.
• EventLoopScheduler: Useful for dedicated work queues. Its use implies that a new reference must be passed to more than one operator, thus making it difficult or impossible to hide behind scheduler façades.
• HistoricalScheduler: Useful for instrumentation and diagnostics.
• VirtualTimeScheduler: Useful for testing and experimentation.
• TestScheduler: Useful for testing and experimentation.

comments

davedev wrote Dec 4, 2012 at 8:58 PM

I wonder if EventLoopScheduler could be hidden behind a Scheduler.AsynchronousLoop façade by supporting the following interface on operators:

public interface IObservableOperator<T> : IObservable<T>
{
IDisposable SubscribeSafe(IScheduler schedulerContext)
}

This would enable an upstream operator to receive information about downstream scheduling as kind of a local query context. Before subscribing, and automatically for Observable.Create and ObservableBase<T>, if the observable implements this interface then it would be used instead of the normal SubscribeSafe method. The core implementation would take Scheduler.AsynchronousLoop as a hint that all operators in the query should use a single instance of EventLoopScheduler, unless an operator's scheduling is explicitly overridden by passing in a scheduler instead of using the overload that passes in a default scheduler.