With Rx, how do I ignore all-except-the-latest value when my Subscribe method is running

后端 未结 9 1545
暖寄归人
暖寄归人 2020-11-29 03:47

Using Reactive Extensions, I want to ignore messages coming from my event stream that occur while my Subscribe method is running. I.e. it sometimes takes me lon

相关标签:
9条回答
  • 2020-11-29 04:01

    Here's a Task based implementation, with cancellation semantics, which doesn't use a subject. Calling dispose allows the subscribed action to cancel processing, if so desired.

        public static IDisposable SampleSubscribe<T>(this IObservable<T> observable, Action<T, CancellationToken> action)
        {
            var cancellation = new CancellationDisposable();
            var token = cancellation.Token;
            Task task = null;
    
            return new CompositeDisposable(
                cancellation,
                observable.Subscribe(value =>
                {
                    if (task == null || task.IsCompleted)
                        task = Task.Factory.StartNew(() => action(value, token), token);
                })
            );
        }
    

    Here's a simple test:

    Observable.Interval(TimeSpan.FromMilliseconds(150))
                          .SampleSubscribe((v, ct) =>
                          {   
                              //cbeck for cancellation, do work
                              for (int i = 0; i < 10 && !ct.IsCancellationRequested; i++)
                                  Thread.Sleep(100);
    
                              Console.WriteLine(v);
                          });
    

    The output:

    0
    7
    14
    21
    28
    35
    
    0 讨论(0)
  • 2020-11-29 04:09

    Thanks to Lee Campbell (of Intro To Rx fame), I now have a working solution using this extension method:

    public static IObservable<T> ObserveLatestOn<T>(this IObservable<T> source, IScheduler scheduler)
    {
        return Observable.Create<T>(observer =>
        {
            Notification<T> outsideNotification = null;
            var gate = new object();
            bool active = false;
            var cancelable = new MultipleAssignmentDisposable();
            var disposable = source.Materialize().Subscribe(thisNotification =>
            {
                bool alreadyActive;
                lock (gate)
                {
                    alreadyActive = active;
                    active = true;
                    outsideNotification = thisNotification;
                }
    
                if (!alreadyActive)
                {
                    cancelable.Disposable = scheduler.Schedule(self =>
                    {
                        Notification<T> localNotification = null;
                        lock (gate)
                        {
                            localNotification = outsideNotification;
                            outsideNotification = null;
                        }
                        localNotification.Accept(observer);
                        bool hasPendingNotification = false;
                        lock (gate)
                        {
                            hasPendingNotification = active = (outsideNotification != null);
                        }
                        if (hasPendingNotification)
                        {
                            self();
                        }
                    });
                }
            });
            return new CompositeDisposable(disposable, cancelable);
        });
    }
    
    0 讨论(0)
  • 2020-11-29 04:13

    With Rx 2.0 RC you can use Chunkify to get an IEnumerable of lists, each containing what was observed since the last MoveNext.

    You can then use ToObservable to convert that back to an IObservable and only pay attention to the last entry in each non-empty list.

    var messages = Observable.Interval(TimeSpan.FromMilliseconds(100));
    
    messages.Chunkify()
            .ToObservable(Scheduler.TaskPool)
            .Where(list => list.Any())
            .Select(list => list.Last())
            .Subscribe(n =>
            {
              Thread.Sleep(TimeSpan.FromMilliseconds(250));
              Console.WriteLine(n);
            });
    
    0 讨论(0)
提交回复
热议问题