强制刷新计数类型Observable.Buffer c#

时间:2015-04-20 08:34:41

标签: c# buffer system.reactive

在这个讨论刷新基于时间的缓冲区的问题的基础上: Force flush to Observable.Buffer c#,我很难解决如何将那里的this答案转换为我按计数而不是按时间缓冲的情况:

var subject = new Subject<Unit>();
var closing = Observable
    .Timer(new TimeSpan(0, 0, 1, 30))
    .Select(x => Unit.Default);

var query =
    mFluxObservable
        .Buffer(() => Observable
            .Amb(subject, closing)
            .Take(1));

我开始使用相同的Amb逻辑,使用“项目计数器”代替计时器,但发现自己正在试图找出如何重置那个的兔子洞。

你可以轻轻地向我推动如何实现我失踪的功能吗?

var flusher = new Subject<Unit>();
var source = Observable.Interval(TimeSpan.FromSeconds(0.1));
var output = source.BufferExceptOnFlush(100, flusher);

我的来源是“热门”,如果这有帮助...

PS:我可以使用Observable.Create和某种内部计数器来解决问题,但不是没有锁定......

3 个答案:

答案 0 :(得分:3)

我认为你可以通过在闭合的observable中使用source并将其与一个刷新的observable合并来实现。以下对我有用:

 var source = new Subject<Unit>();
 var flush = new Subject<Unit>();

 // close buffer every 3 values or when a flush value arrives
 var closing = source.Buffer(3) 
            .Select(x => Unit.Default)
            .Merge(flush);

 var query = source.Buffer(() => closing)
         .Subscribe(Console.WriteLine);

// some test values
source.OnNext(Unit.Default);
source.OnNext(Unit.Default);
source.OnNext(Unit.Default);
source.OnNext(Unit.Default);

// flush buffer
flush.OnNext(Unit.Default);

答案 1 :(得分:0)

这是我到目前为止所得到的:

var flush = new Subject<Unit>();
var source = Observable.Interval(TimeSpan.FromSeconds(1))
            .Select(_ => Unit.Default).Publish().RefCount();
var closer = CloseGenerator(source, flush, 5);
source.Buffer(closer)

//...

private IObservable<Unit> CloseGenerator<T>(IObservable<T> source, 
                                             IObservable<Unit> flusher, int count)
{
     return Observable.CombineLatest(
                        source.Select((_, i) => i), 
                        flusher.Select((_, i) => i).StartWith(-1))
             .Select(ar => Tuple.Create(ar[0], ar[1]))
             .Scan(Tuple.Create(-1, -1), (prev, next) =>
                 {
                     if(next.Item2 != prev.Item2 || next.Item1 == prev.Item1 + count)
                         return next;
                     else
                         return prev;
                 }
             )
             .DistinctUntilChanged().Skip(1) //This is 'DistinctExceptFirst'
             .Select(_ => Unit.Default);
}

答案 2 :(得分:0)

我认为Observable.Create<T>解决方案没有错。在这种情况下,我认为这个扩展应该工作

public static IObservable<IList<T>> BufferExceptOnFlush<T>(this IObservable<T> source,IObservable<Unit> flusher, int bufferSize)
{
 return Observable.Create<IList<T>>(observer =>
 {
     var shared = source.Publish();
     var closing = shared.Buffer(bufferSize).Select(x => Unit.Default);
     var query = shared.Buffer(() => flusher.Amb(closing).Take(1)).SubscribeSafe(observer);
     return new CompositeDisposable(query, shared.Connect());
 });

我还没有测试过,但会启用这样的用法

var query = myFluxObservable.BufferExceptOnFlush(myFlusher, 5);

由于没有双重订阅

,它适用于热和冷可观测量