В приложении С# (.NET 4.0) я использую Reactive Extensions (2.0.20823.0) для создания временных границ для группировки событий в агрегированные значения. Чтобы упростить запросы к результирующей базе данных, эти границы должны быть выровнены в полные часы (или секунды в примере ниже).
Использование Observable.Timer()
:
var time = DefaultScheduler.Instance;
var start = new DateTimeOffset(time.Now.DateTime, time.Now.Offset);
var span = TimeSpan.FromSeconds(1);
start -= TimeSpan.FromTicks(start.Ticks % 10000000);
start += span;
var boundary = Observable.Timer(start, span, time);
boundary.Select(i => start + TimeSpan.FromSeconds(i * span.TotalSeconds))
.Subscribe(t => Console.WriteLine("ideal: " + t.ToString("HH:mm:ss.fff")));
boundary.Select(i => time.Now)
.Subscribe(t => Console.WriteLine("actual: " + t.ToString("HH:mm:ss.fff")));
Вы можете видеть, что предполагаемое и фактическое время таймера гаснет довольно сильно:
ideal: 10:06:40.000
actual: 10:06:40.034
actual: 10:06:41.048
ideal: 10:06:41.000
actual: 10:06:42.055
ideal: 10:06:42.000
ideal: 10:06:43.000
actual: 10:06:43.067
actual: 10:06:44.081
ideal: 10:06:44.000
ideal: 10:06:45.000
actual: 10:06:45.095
actual: 10:06:46.109
ideal: 10:06:46.000
ideal: 10:06:47.000
actual: 10:06:47.123
actual: 10:06:48.137
ideal: 10:06:48.000
...
Я также использую HistoricalScheduler
, и, конечно, проблем у меня нет. Я могу терпеть небольшие неточности, и мне не нужно заботиться о изменениях системных часов. Нет тяжелых операций, вызванных этими Observables.
Кроме того, я знаю, что в этом сообщении в блоге есть продолжительное обсуждение проблем с дрейфом таймера RX, но я, похоже, не в состоянии чтобы обернуть вокруг себя голову.
Каким будет правильный способ периодического планирования Observable
без систематического дрейфа таймера?