2014-04-04 30 views
2

我有一个非常琐碎的序列,我试图通过批量处理事件来提高它的效率。具有时间和计数条件的缓冲器操作员似乎符合我的要求,除了一个小的细微差别。当您使用此重载时,无论缓冲区中是否有任何项目,预订都会在指定的时间延迟后收到通知。这真的很烦人,因为大部分时间我的订阅从缓冲区操作符中获得一个空列表。考虑到它是一个多线程应用程序,用户在UI线程上,结果并不是批量处理项目的最佳方法。我想知道是否有一种方法可以使用可用的操作符创建一个序列,当缓冲区中存在一定数量的项目时,或者某个时间已经过去时,该序列将触发,但是当且仅当存在任何项时缓冲区。我知道我可以做这样的事情:具有计数和时间条件的缓冲区操作符

sequence.Buffer(TimeSpan.FromSeconds(5), 1).Where(e=>e.Count > 0) 

但我不知道是否有另一种方式来做到这一点,导致莫名其妙我觉得这不是最好的办法。

回答

1

我看不出有什么理由担心这个 - 你有一个习惯性的解决方案。一个空的缓冲区是信息,所以框架实现返回它是合理的。无论如何,任何其他方法都会有效地做同样的事情。

当我发现自己使用小群体的标准操作符时,我经常用更具说明性的扩展方法来包装它们。例如: -

public static class ObservableExtensions 
{ 
    public static IObservable<IList<T>> ToNonEmptyBuffers<T>(
     this IObservable<T> source, 
     TimeSpan timespan, 
     int count, 
     IScheduler scheduler = null) 
    { 
     scheduler = scheduler ?? Scheduler.Default; 
     return source.Buffer(timespan, count, scheduler ?? Scheduler.Default) 
        .Where(buffer => buffer.Count > 0); 
    } 
} 

允许:

sequence.ToNonEmptyBuffers(TimeSpan.FromSeconds(5), 1); 
0

对于 “RX-I-性” 的缘故,我扔在下面的一堆。

就个人而言,我认为詹姆斯的答案已经足够了(可能在很多情况下都会更好)。唯一的区别(就输出而言),只有在产生新项目时才启动缓冲计时器。这就是为什么我们不需要过滤掉空的缓冲区。这就是说,这可能不是最有效的解决方案。它只是在这里展示组合的力量。

var batches = source 
     .GroupByUntil(
      // This means we're not really grouping, but windowing. 
      // granted, if we needed to group our batches, this is useful! 
      x => 0, 
      group => Observable.Amb(
       // this means we get a max of 11 per batch 
       group.Skip(10), 
       // This means we get a max batch time of 10 seconds 
       group.Take(1).Delay(TimeSpan.FromSeconds(10)) 
     )) 
     // Since GroupByUntil gives us windows, we can ToArray them. 
     .SelectMany(x => x.ToArray()); 
相关问题