Skip to content

Schedulers

Nicolás Seijas edited this page Jul 28, 2026 · 1 revision

Schedulers

A scheduler is an IStateScheduler. It has one operation:

void Post(Action flush);

Rambla gives the flush to the scheduler. The scheduler runs the flush on the UI thread, immediately or later. The core has no reference to a UI framework. All UI integration is a scheduler.

The schedulers in the core package

Scheduler Behavior Use it for
ImmediateStateScheduler Runs the flush on the thread that writes. Tests, and states that only the UI thread writes.
SynchronizationContextStateScheduler Posts the flush to a captured SynchronizationContext. A UI framework that has no adapter.
ThrottlingStateScheduler Puts a maximum on the flush rate of a different scheduler. A high and continuous update rate.

The adapter packages

Package Type UI framework
Rambla.Wpf Rambla.Wpf.DispatcherStateScheduler WPF
Rambla.Avalonia Rambla.Avalonia.DispatcherStateScheduler Avalonia 11.0 and later

Each adapter posts the flush at Background priority. Thus the state operations do not stop the input and the render operations.

WPF

using Rambla.Wpf;

DispatcherStateScheduler.InstallAsDefault();                     // no rate limit
_scheduler = DispatcherStateScheduler.InstallThrottledAsDefault(60);   // 60 flushes each second

Avalonia

using Rambla.Avalonia;

DispatcherStateScheduler.InstallAsDefault();
_scheduler = DispatcherStateScheduler.InstallThrottledAsDefault(60);

The Avalonia adapter has a build reference to Avalonia 11.0. That is the minimum version. Applications that use Avalonia 11.x and 12.x both operate correctly. The adapter accepts an IDispatcher. Thus a test can give a substitute dispatcher and examine the posted flushes without a UI thread.

Limit the refresh rate

The adapters post each flush as soon as the dispatcher is available. Under a continuous load, the number of flushes stays high. The ThrottlingStateScheduler puts a maximum on that number.

using Rambla.Scheduling;

// Wrap the scheduler that reaches the UI.
var scheduler = new ThrottlingStateScheduler(
    new DispatcherStateScheduler(dispatcher),
    maxRefreshRate: 60);

var vm = new MarketViewModel(scheduler);

If you do not give a rate, the scheduler uses RamblaOptions.Default.MaxRefreshRate. The default value is 60.

RamblaOptions.Default.MaxRefreshRate = 30;

The rules of the throttling scheduler

  1. The rate is a maximum. The scheduler makes a maximum of MaxRefreshRate releases in one second. The interval of the operating system timer can make the true rate lower, but never higher.
  2. The first post is immediate. After an idle interval, the scheduler releases the first post immediately. Thus one update does not wait for a full interval. The scheduler delays only a continuous sequence of posts.
  3. The scheduler does not discard a flush. Each posted flush runs, in this release or in a subsequent release.
  4. The scheduler holds the timer. The scheduler is IDisposable. Dispose it at shutdown, after the writers stop.

Warning: after you dispose the scheduler, Post makes an ObjectDisposedException. The scheduler does not discard the flush quietly, because a discarded flush stops all subsequent notifications of that state.

Which scheduler do I use?

  • The UI thread writes the state: ImmediateStateScheduler.
  • A background thread writes the state at a low rate: the adapter for your UI framework.
  • A background thread writes the state at a high and continuous rate: the adapter in a ThrottlingStateScheduler.

Use Diagnostics to measure the result of your selection.

Clone this wiki locally