我有一个极其繁琐的序列,我试图通过批量处理事件来提高效率。具有时间和计数条件的缓冲区运算符似乎符合我的要求,除了一个小的细微差别。当您使用此重载时,无论缓冲区中是否有任何项目,都会在指定的时间延迟后通知订阅。这变得非常烦人,因为我的订阅大部分时间从缓冲区运算符获取一个空列表。考虑到它是一个多线程应用程序,其中订户在UI线程上,结果证明这不是批量处理项目的最佳方法。我想知道是否有一种方法可以使用可用的运算符来创建一个序列,当缓冲区中存在一定数量的项目时,或者当某个时间已经过去时,将会触发,但是当且仅当有任何项目时缓冲区。我知道我可以这样做:
sequence.Buffer(TimeSpan.FromSeconds(5), 1).Where(e=>e.Count > 0)
但是我想知道是否还有其他方法可以做到这一点,因为我觉得这不是最好的方式。
答案 0 :(得分:1)
我无法理解这个问题 - 你有一个惯用的解决方案。空缓冲区是信息,因此框架实现返回它是合理的。无论如何,任何其他方法都会有效地做同样的事情。
当我发现自己使用一小组标准运算符时,我经常将它们包含在一个更具说明性的扩展方法中。 E.g:
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);
答案 1 :(得分:0)
为了&#34; Rx-i-ness&#34;我把以下内容扔进了堆里。
个人而言,我认为詹姆斯&#39;答案就足够了(在很多场景中可能更好)。唯一的区别(就输出而言)是缓冲计时器仅在产生新项目时启动。这就是我们不需要过滤掉空缓冲区的原因。话虽如此,这可能不是最有效的解决方案。它就在这里展示作曲的力量。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());