我正在构建我的第一个Reactive.NET应用程序,并且正在努力管理两组observable。
首先,我在两个集合中轮询服务器。我有两个“响铃”时间(更快更慢):一个每秒发射一个,每15秒发射一个。我注意到,如果服务器需要一段时间来处理其中一个响铃中的一个呼叫,它将立即“赶上”并在呼叫完成后连续触发事件(通过超时或其他方式)。因此,如果我每秒开火并且有30秒的延迟,则一旦延迟完成(假设没有其他进一步的延迟),订阅将通过触发30次来恢复。这不是首选,因为我希望将对服务器的调用保持在最低限度,因此每个环的每个时间帧严格遵守。也就是说,如果有30秒的延迟,我不希望一旦延迟过去就用电话轰炸服务器。
我使用Sample
解决了这个问题。而且,实际上,一切都运行良好,除了现在应用程序启动时,外环有一个延迟,直到15秒才看到任何输出。使用1秒钟的戒指,我使用StartsWith(-1)
来解决这个问题,但我似乎无法用外(慢)环来解决这个问题。
这是我的代码:
var fast = TimeSpan.FromSeconds(1);
var slow = TimeSpan.FromSeconds(15);
var application = Observable.Interval(fast)
.Sample(fast)
.StartWith(-1)
.Timestamp()
.Window(slow)
.Sample(slow)
.Subscribe(window =>
{
// Outer (slower) ring: ...
window.Subscribe(x =>
{
// Inner (faster) ring: ...
});
});
所以,真的,问题是:
编辑:
基于@ yohanmishkin的回答,这是我正在使用的代码:
var poll = Observable.Interval(TimeSpan.FromSeconds(1));
var lessFrequentPoll = Observable.Interval(TimeSpan.FromSeconds(15));
poll.Subscribe(o => application.UpdateFrequent(o));
lessFrequentPoll.Subscribe(o => application.UpdateLessFrequent(o));
using (new CompositeDisposable(poll, lessFrequentPoll))
{
// ...
}
正如答案中所提到的,当我第一次启动Rx时,我确实使用了这个,但我最初在想(由于我对Rx的原始理解),对于每个订阅,我必须嵌套using
上下文,并希望避免这种情况。所以,如果我最终得到5个“响铃”时间,我会有5个嵌套using
,这对我来说并不好看。使用CompositeDisposable
可以缓解这种情况。
答案 0 :(得分:1)
在这种情况下,您可能需要创建两个单独的observable并分别订阅它们的应用程序。
以下是一个例子:
CombineLatest
如果你仍然希望将两个区间组合成一个流,Rx提供了大量的操作符(Merge,Zip,CombineLatest ......)。
在您的情况下,您可能需要查看WithLatestFrom
或WithLatestFrom
。您可以看到它们如何工作的可视化here (CombinedLatest)或here (WithLatestFrom)。
示例可能是使用var combinedPoll =
poll
.WithLatestFrom(
lessFrequentPoll,
(pollEvent, lessFrequentPollEvent) =>
new CombinedEvent(pollEvent, lessFrequentEvent)
);
combinedPoll.Subscribe(o =>
{
application.UpdateFrequent(o.FrequentEvent);
application.UpdateLessFrequent(o.LessFrequentEvent);
});
创建一个新流,该流发出一些对象,该对象组合了您的应用程序随后可以订阅的两个区间可观察对象。
Private Sub Detail_Format(Cancel As Integer, FormatCount As Integer)
If Forms!DASHBOARD!NavigationSubform.Form!rptMain.chkWaBox.Value = True Then
Detail.Visible = True
End If
End Sub
进一步阅读
答案 1 :(得分:0)
我发现这种事情对Rx来说有点棘手。似乎订阅的作品不应该真正具有修改序列本身的副作用。但是,这就是你所需要的,因为如果工作运行缓慢(服务很慢),你需要减少轮询频率。
我认为 IScheduler.Schedule()
的各种递归重载旨在支持这种事情。请参阅http://www.introtorx.com/Content/v1.0.10621.0/15_SchedulingAndThreading.html。
这个想法是这样的:
private static IObservable<int> PollServer(IScheduler scheduler)
{
return Observable.Create<int>(
observer =>
{
var cts = new CancellationTokenSource();
var token = cts.Token;
// Make initial call immediately
var scheduled = scheduler.Schedule(
TimeSpan.Zero,
async action =>
{
try
{
var res = await CallServer(token);
observer.OnNext(res);
// Trigger another iteration after poll delay
action(TimeSpan.FromSeconds(1));
}
catch (Exception ex)
{
observer.OnError(ex);
}
});
// Discontinue polling when observable is disposed
return () =>
{
cts.Cancel();
scheduled.Dispose();
};
});
}
private static async Task<int> CallServer(CancellationToken token)
{
// Remote service call
await Task.Delay(100);
return 42;
}
这显然只提供了你的“慢速戒指”的代码,但希望它可以让你知道你需要什么。