C# Rx框架:在超时时执行操作,而不中断原始可观察序列
给定一个可观测源,通过轮询低级设备的(状态变化)生成C# Rx框架:在超时时执行操作,而不中断原始可观察序列,c#,timeout,system.reactive,C#,Timeout,System.reactive,给定一个可观测源,通过轮询低级设备的(状态变化)生成 // observable source metacode: IObservable<DeviceState> source = Observable.Interval(TimeSpan.FromSeconds(0.5)) .Select(tick => new DeviceState(_device.ReadValue())) .DistinctUntilChanged(); 。。。我需要在x秒的源代码“
// observable source metacode:
IObservable<DeviceState> source = Observable.Interval(TimeSpan.FromSeconds(0.5))
.Select(tick => new DeviceState(_device.ReadValue()))
.DistinctUntilChanged();
。。。我需要在x秒的源代码“不活动”后执行自定义操作,而不中断对源代码的订阅。大概是这样的:
// UI metacode:
service.GetObservableDeviceStates()
.DoOnTimeout(TimeSpan.FromSeconds(x), () => viewModel.CurrentState = "Idle")
.Subscribe(state => viewModel.CurrentState = state.ToString());
最佳实践是什么?想到的可能解决方案有(我是Rx noob):
service.GetObservableDeviceStates()
.Do(onNext)
.Throttle(TimeSpan.FromSeconds(x))
.Subscribe(onTimeout);
编辑2(警告)
如果onNext和onTimeout更新UI组件,为了避免交叉线程异常,需要两个ObserveOn(uiSynchronizationContext),因为Throttle在另一个线程上工作
service.GetObservableDeviceStates()
.ObserveOn(uiSynchronizationContext)
.Do(onNext)
.Throttle(TimeSpan.FromSeconds(x))
.ObserveOn(uiSynchronizationContext)
.Subscribe(onTimeout);
超时或多或少是指表示单个异步操作的可观察对象,例如,如果所述可观察对象在一定时间内未通知您,则返回默认值或
OnError
你要找的接线员是,尽管一开始看起来可能不是这样Throttle(p)
提供一个流,当源流没有为时段p
生成值时,该流会生成一个值
与现有代码并行,您可以使用
source.Throttle(period).Do(…副作用)
我个人会避免使用Do方法。它确实使本例中的代码变得相当简单,但我发现一旦使用“Do”潜入代码库,您很快就会得到意大利面条
<>你也可以考虑使用恩布、定时器、TakeUntil、油门等的组合来获得你正在寻找的结果,并且仍然保持单元格*。或者简单地说,我假设理想情况下您希望获得一系列状态值,而不需要在代码中放入计时器(即,将其卸载到服务)
它很有魅力,谢谢!我一直使用Throttle来丢弃元素(并在最终订阅中使用剩余的元素),从不调用“onPause”回调:)+1,因为人们无法充分强调
Do
是一种邪恶。不过,我觉得在这种情况下,Timestamp
|>combinelatetest
的性能可能会更好一些。感觉如何?我们在一家应用科学公司工作。只是提供一个证据。在我们的行业中,基于感觉宣布性能建议是一个需要停止的问题。神圣的巫术,蝙蝠侠!李开复说得对。我会因此成为一个更好的人。:)您可以将UI线程调度程序指定为要限制的参数,以便在那里运行限制计时器,以避免额外的ObserveOn跃点。@BartDeSmet我已尝试限制(x,scheduler.CurrentThread),但我正在失去UI响应。。。就我而言,ObserveOn工作得更好
service.GetObservableDeviceStates()
.ObserveOn(uiSynchronizationContext)
.Do(onNext)
.Throttle(TimeSpan.FromSeconds(x))
.ObserveOn(uiSynchronizationContext)
.Subscribe(onTimeout);
public IObservable<DeviceStatus> GetObservableDeviceStates(TimeSpan silencePeriod)
{
return Observable.Create<DeviceStatus>(
o=>
{
var idle = Observable.Timer(silencePeriod).Select(_=>new DeviceStatus("Idle"));
var polledStatus = Observable.Interval(TimeSpan.FromSeconds(0.5))
.Select(tick => new DeviceStatus(_device.ReadValue()))
.DistinctUntilChanged()
.Publish();
var subscription = (from status in polledStatus
from cont in Observable.Return(status).Concat(idle.TakeUntil(polledStatus))
select cont)
.Subscribe(o);
return new CompositeDisposable(subscription, polledStatus.Connect());
});
}
// UI metacode:
service.GetObservableDeviceStates(TimeSpan.FromSeconds(2))
.Subscribe(state => viewModel.CurrentState = state.ToString());