Rx滑动缓冲区

时间:2019-06-15 22:19:32

标签: c# system.reactive

我正在尝试模拟一种情况,即传感器读数每隔一秒钟触发一次。然后,我想收集最近三秒钟内发生的所有读数,最多不超过5个读数,并输出该列表。

这行不通,但我不明白为什么。

public static class Extensions
{    
    public static IObservable<IList<T>> SlidingBuffer<T>(this IObservable<T> obs, TimeSpan span, int max)
    {
        return Observable.Create<IList<T>>(cl =>
        {
            var acc = new List<T>();
            return obs.Buffer(span)
            .Subscribe(next =>
            {
                if (next.Count == 0) //no activity in time span
                    {
                    cl.OnNext(acc);
                    acc.Clear();
                }
                else
                {
                    acc.AddRange(next);
                    if (acc.Count >= max) //max items collected
                        {
                        cl.OnNext(acc);
                        acc.Clear();
                    }
                }
            }, err => cl.OnError(err), () => { cl.OnNext(acc); cl.OnCompleted(); });
        });
    }
}

public class SensorReading
{
    public int Time { get; set; }
    public int Value { get; set; }
    public override string ToString() => new { Time, Value }.ToString();
    public override bool Equals(object obj) =>
        obj is SensorReading other && this.Time == other.Time && this.Value == other.Value;

    public override int GetHashCode() => Time.GetHashCode() ^ Value.GetHashCode();
}

public static class Program
{
    public static void Main(string[] args)
    { 
        var els = new EventLoopScheduler();
        var dispatcher = new EventLoopScheduler();

        var obs = SimulateLiveData()
        .SlidingBuffer(new System.TimeSpan(3000), 5)
        .SubscribeOn(els)
        .ObserveOn(dispatcher)
        .Select((sr) => DoCalc(sr))
        .Subscribe();       
    }

    public static IEnumerable<SensorReading> DoCalc(IEnumerable<SensorReading> sr)
    {
        sr.Dump(); // Dump is linqpad Dump
        return sr;
    }


    private static readonly SensorReading[] HistoricData = new[]
    {
            new SensorReading { Time = 1, Value = 0 },
            new SensorReading { Time = 2, Value = 20 },
            new SensorReading { Time = 3, Value = 15 },
            new SensorReading { Time = 4, Value = 30 },
            new SensorReading { Time = 5, Value = 45 }, // Here we crossed the threshold upward
            new SensorReading { Time = 6, Value = 50 },
            new SensorReading { Time = 7, Value = 30 }, // Here we crossed downward. Note that the current query logic only detects upward swings.
            new SensorReading { Time = 8, Value = 35 },
            new SensorReading { Time = 9, Value = 60 }, // Here we crossed upward again
            new SensorReading { Time = 10, Value = 20 }
        };

    private static IObservable<SensorReading> SimulateLiveData()
    {
        return ToObservableInterval(HistoricData, TimeSpan.FromMilliseconds(1000));
    }

    private static IObservable<T> ToObservableInterval<T>(IEnumerable<T> source, TimeSpan period)
    {
        return Observable.Using(
            source.GetEnumerator,
            it => Observable.Generate(
                default(object),
                _ => it.MoveNext(),
                _ => _,
                _ =>
                {
                    //Console.WriteLine("Input {0}", it.Current);
                    return it.Current;
                },
                _ => period));
    }
}

0 个答案:

没有答案