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):

  • (即使不是那么可读)
  • 玩弄
  • 在没有任何更改时返回一些特殊的“服务端”(而不是使用DistinctUntilChanged)并在UI代码中处理:

    服务。GetObservableDeviceEstates() .订阅(状态=> viewModel.CurrentState=state.Special?“Idle”:state.ToString()

  • 编辑:据报道,解决方案是:

            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());