多くのタイマーが必要ですか?20 個のコレクションがある場合、20 個のタイマーをすべて同じ時点で起動するように作成しますか? 同じスレッド/スケジューラー上ですか?
DoWork
それとも、すべての期間で foreachを使用したいですか?
すなわち
from thing in things
from x in Observable.Interval(thing.Interval)
select DoWork(thing.Uri)
対。
Observable.Interval(interval)
.Select(_=>
{
foreach(var thing in Things)
{
DoWork(thing);
}
})
将来的に仕事をする方法はたくさんあります。
- スケジューラを直接使用して、将来実行される作業をスケジュールできます。
- Observable.Timer を使用して、将来の指定された時間に 1 つの値を生成するシーケンスを持つことができます。
- Observable.Interval を使用して、指定された期間ごとに多くの値を生成するシーケンスを持つことができます。
したがって、これは別の質問を紹介します。ポーリング時間が 60 秒で、機能を実行する場合は 5 秒かかります。次のポーリングは 55 秒後か 60 秒後か? ここで、1 つの回答は Rx シーケンスを使用することを示し、もう 1 つの回答はおそらく定期的なスケジューリングを使用することを示しています。
次の質問は、DoWork が値を返すかどうかです。現在、そうではないようです*。この場合、最も適切なことは定期スケジューラを活用することだと思います (Rx v2 を想定)。
var things = new []{
new Thing{Name="google", Uri = new Uri("http://google.com"), StartTime=DateTimeOffset.Now.AddSeconds(1), Interval=3},
new Thing{Name="bing", Uri = new Uri("http://bing.com"), StartTime=DateTimeOffset.Now.AddSeconds(1), Interval=3}
};
var scheduler = Scheduler.Default;
var scheduledWork = new CompositeDisposable();
foreach (var thing in things)
{
scheduledWork.Add( scheduler.SchedulePeriodic(thing, TimeSpan.FromSeconds(thing.Interval), t=>DoWork(t.Uri)));
}
//Just showing that I can cancel this i.e. clean up my resources.
scheduler.Schedule(TimeSpan.FromSeconds(10), ()=>scheduledWork.Dispose());
これにより、それぞれの処理が定期的に (ドリフトなしで) 独自の間隔でスケジュールされ、キャンセルが提供されます。
必要に応じて、これをクエリにアップグレードできます
var scheduledWork = from thing in things
select scheduler.SchedulePeriodic(thing, TimeSpan.FromSeconds(thing.Interval), t=>DoWork(t.Uri));
var work = new CompositeDisposable(scheduledWork);
StartTime
これらのクエリの問題は、要件を満たしていないことです。面倒なことに、このCcheduler.SchedulePeriodic
メソッドは開始オフセットを持つためのオーバーロードも提供していません。
ただし、Observable.Timer
オペレーターはこれを提供します。また、ドリフトしないスケジューリング機能を内部的に活用します。クエリを再構築するにObservable.Timer
は、次のようにします。
var urisToPoll = from thing in things.ToObservable()
from _ in Observable.Timer(thing.StartTime, TimeSpan.FromSeconds(thing.Interval))
select thing;
var subscription = urisToPoll.Subscribe(t=>DoWork(t.Uri));
これで、ドリフトを回避する優れたインターフェイスが完成しました。ただし、ここでの作業は逐次的に行われると思います (多数の DoWork アクションが同時に呼び出される場合)。
*理想的には、このような副作用の記述を避けようとしますが、あなたの要件が 100% わかっているわけではありません。
編集
DoWork への呼び出しは並行して行う必要があるようです。そのため、もう少し処理を行う必要があります。理想的には DoWork を asnyc にしますが、それができない場合は、作成するまで偽装することができます。
var polling = from thing in things.ToObservable()
from _ in Observable.Timer(thing.StartTime, TimeSpan.FromSeconds(thing.Interval))
from result in Observable.Start(()=>DoWork(thing.Uri))
select result;
var subscription = polling.Subscribe(); //Ignore the bool results?