Reactive Extensions,立即触发OnNext,然后在一段时间内触发

时间:2012-06-25 14:22:32

标签: c# system.reactive observable

我有一个web服务,我希望在布尔值设置为true后立即查询更新,然后每5分钟重新检查一次。

这是我目前的观察结果:

        _queryDisposable = Observable
            .Interval(TimeSpan.FromMinutes(5))
            .ObserveOn(Scheduler.ThreadPool)
            .Where(i => IsProcessing)     // IsProcessing is the bool value
            .Subscribe(GetFeeds, OnError, OnComplete);

这个观察者将检查IsProcessing bool是否每5分钟为真或假,然后如果为真则调用GetFeeds

我能想到达到预期效果的唯一方法是使IsProcessing成为属性支持的字段,并使用以下两个可观察对象进行处理:

    private bool _isProcessing;

    public bool IsProcessing
    {
        get { return _isProcessing; }
        set
        {
            if (_isProcessing == value)
                return;

            _isProcessing = value;

            if (!value)
            {
                if(_queryDisposable != null)
                    _queryDisposable.Dispose();
                _queryDisposable = null;
            }
            else
            {
                Observable
                    .Range(0,1)
                    .ObserveOn(Scheduler.ThreadPool)
                    .Subscribe(GetFeedsSafe, OnError, OnComplete);

                _queryDisposable = Observable
                    .Interval(TimeSpan.FromMinutes(5))
                    .ObserveOn(Scheduler.ThreadPool)
                    .Subscribe(GetFeedsSafe, OnError, OnComplete);
            }
        }
    }

我不认为这是一个非常优雅的解决方案,所以我想知道是否有更好的方法来实现这种效果?

3 个答案:

答案 0 :(得分:3)

我是否遗漏了某些内容,或者您​​是否只是在启动Observable之前立即致电订阅?

    Subscribe(GetFeeds, OnError, OnComplete);
    // Or perhaps, if you want it to be async,
    new TaskFactory().StartNew(()=>Subscribe(GetFeeds, OnError, OnComplete));

    _queryDisposable = Observable
        .Interval(TimeSpan.FromMinutes(5))
        .ObserveOn(Scheduler.ThreadPool)
        .Where(i => IsProcessing)     // IsProcessing is the bool value
        .Subscribe(GetFeeds, OnError, OnComplete);

编辑:Pure Rx,来自http://social.msdn.microsoft.com/Forums/sa/rx/thread/c4acaf34-3136-4206-a6f9-ef5afba74b2b

Observable.Interval(TimeSpan.FromMinutes(5))
        .StartWith(-1L)
        .ObserveOn(Scheduler.ThreadPool)
        .Where(i => IsProcessing)     // IsProcessing is the bool value
        .Subscribe(GetFeeds, OnError, OnComplete);

答案 1 :(得分:2)

要立即开始排序并在给定时间内仍然生成一个值,您有两个选项:

  1. Observable.Interval(TimeSpan.FromMinutes(5))。StartWith(-1)
  2. Observable.Timer(TimeSpan.FromMinutes(0),TimeSpan.FromMinutes(5))
  3. 接下来我假设您想要在IsProcessing值设置为false时取消计时器,您还希望在将序列设置回true时重新启动序列。无论何时设置IsProcessing值,上述两个答案都会运行5分钟的间隔。如果设置IsProcessing = true,序列将启动,如果一分钟后您设置IsProcessing = false然后IsProcessing = true,您仍需要等待4分钟才能再次查询。我认为这不是你想要的?

    所以我们希望这可以触发财产变更。 @SPFiredrake很好地建议INPC并将事件转换为Observable序列。周围有很多小片段可以帮助你做到这一点。假设我们使用的是一个扩展方法PropertyChanges,我们可以编写这个非常简单的查询。

    var isProcessingValues = this.PropertyChanges(x=>x.IsProcessing);
    isProcessingValues
        .Where(isProcessing=>isProcessing)
        .SelectMany(_=> 
            Observable.Timer(TimeSpan.Zero, TimeSpan.FromMinutes(5))
                      .TakeUntil(isProcessingValues.Where(isProcessing=>!isProcessing))
        )
        .Select(_=>GetFeeds())  //What does GetFeeds actually return?
        .SubscribeOn(Scheduler.NewThread)
        .Subscribe(feedData=>Console.WriteLine(feedData), 
            ex=>Console.WriteLine (ex),
            ()=>Console.WriteLine (completed));
    

    慢慢地踩过这个:

    1. 当IsProcessing属性更改时,将新值推送到序列中(isProcessingValues)
    2. 当序列值为true时,启动一个现在每5分钟产生一个值的计时器序列。
    3. 如果isProcessingValues序列产生的值为
    4. ,则应停止计时器序列
    5. 每次计时器滴答时(当IsProcess设置为true时,每隔5分钟设置为真),请调用GetFeeds
    6. 确保我们的序列在不同的线程上订阅(不阻止)。如果不是必需,请删除。
    7. 从Feed中获取数据并对其执行操作。

答案 2 :(得分:0)

你有没有想过让IsProcessing变量触发一个你可以听的prop改变的事件?

var processing = Observable
    .FromEventPattern<PropertyChangedEventArgs>(this, "PropertyChanged")
    .Where(tr => tr.EventArgs.Property == "IsProcessing" && ((Type)tr.Sender).IsProcessing);

_queryDisposable = Observable
    .Interval(TimeSpan.FromMinutes(5))
    .ObserveOn(Scheduler.ThreadPool)
    .And(processing) // Will only fire when both sequences have an available value.
    .Subscribe(GetFeeds, OnError, OnComplete);

这也确保了如果它正在处理,它只会触发一次因为处理observable一次只提供一个值(每个IsProcessing改为true)所以你不必担心如果它在5分钟后仍然处理,它将再次发射。