How to throttle event stream using RX?

前端 未结 8 780
终归单人心
终归单人心 2020-11-27 04:04

I want to effectively throttle an event stream, so that my delegate is called when the first event is received but then not for 1 second if subsequent events are received. A

8条回答
  •  Happy的楠姐
    2020-11-27 04:31

    Inspired by Bluelings answer I provide here a version that compiles with Reactive Extensions 2.2.5.

    This particular version counts the number of samples and also provide the last sampled value. To do this the following class is used:

    class Sample {
    
      public Sample(T lastValue, Int32 count) {
        LastValue = lastValue;
        Count = count;
      }
    
      public T LastValue { get; private set; }
    
      public Int32 Count { get; private set; }
    
    }
    

    Here is the operator:

    public static IObservable> SampleResponsive(this IObservable source, TimeSpan interval, IScheduler scheduler = null) {
      if (source == null)
        throw new ArgumentNullException(nameof(source));
      return Observable.Create>(
        observer => {
          var gate = new Object();
          var lastSampleValue = default(T);
          var lastSampleTime = default(DateTime);
          var sampleCount = 0;
          var scheduledTask = new SerialDisposable();
          return new CompositeDisposable(
            source.Subscribe(
              value => {
                lock (gate) {
                  var now = DateTime.UtcNow;
                  var elapsed = now - lastSampleTime;
                  if (elapsed >= interval) {
                    observer.OnNext(new Sample(value, 1));
                    lastSampleValue = value;
                    lastSampleTime = now;
                    sampleCount = 0;
                  }
                  else {
                    if (scheduledTask.Disposable == null) {
                      scheduledTask.Disposable = (scheduler ?? Scheduler.Default).Schedule(
                        interval - elapsed,
                        () => {
                          lock (gate) {
                            if (sampleCount > 0) {
                              lastSampleTime = DateTime.UtcNow;
                              observer.OnNext(new Sample(lastSampleValue, sampleCount));
                              sampleCount = 0;
                            }
                            scheduledTask.Disposable = null;
                          }
                        }
                      );
                    }
                    lastSampleValue = value;
                    sampleCount += 1;
                  }
                }
              },
              error => {
                if (sampleCount > 0)
                  observer.OnNext(new Sample(lastSampleValue, sampleCount));
                observer.OnError(error);
              },
              () => {
                if (sampleCount > 0)
                  observer.OnNext(new Sample(lastSampleValue, sampleCount));
                observer.OnCompleted();
              }
            ),
            scheduledTask
          );
        }
      );
    }
    

提交回复
热议问题