C# 具有计数和时间条件的缓冲区运算符
我有一个非常健谈的序列,我试图通过成批处理事件来提高它的效率。带有时间和计数条件的缓冲区操作符似乎符合我的要求,只是有一点细微差别。使用此重载时,无论缓冲区中是否有任何项,都会在指定的时间延迟后通知订阅。这真的很烦人,因为大多数时候我的订阅从缓冲区操作符得到一个空列表。考虑到它是一个多线程应用程序,订阅者位于UI线程上,因此它不是批量处理项目的最佳方法。我想知道是否有一种方法可以使用可用的操作符来创建一个序列,当缓冲区中存在一定数量的项时,或者当某个时间已经过去时,但是当且仅当缓冲区中有任何项时,该序列才会触发。我知道我可以这样做:C# 具有计数和时间条件的缓冲区运算符,c#,.net,system.reactive,C#,.net,System.reactive,我有一个非常健谈的序列,我试图通过成批处理事件来提高它的效率。带有时间和计数条件的缓冲区操作符似乎符合我的要求,只是有一点细微差别。使用此重载时,无论缓冲区中是否有任何项,都会在指定的时间延迟后通知订阅。这真的很烦人,因为大多数时候我的订阅从缓冲区操作符得到一个空列表。考虑到它是一个多线程应用程序,订阅者位于UI线程上,因此它不是批量处理项目的最佳方法。我想知道是否有一种方法可以使用可用的操作符来创建一个序列,当缓冲区中存在一定数量的项时,或者当某个时间已经过去时,但是当且仅当缓冲区中有任何项时
sequence.Buffer(TimeSpan.FromSeconds(5), 1).Where(e=>e.Count > 0)
但我想知道是否还有其他方法可以做到这一点,因为不知何故,我觉得这不是最好的方法。我看不出有什么理由担心这一点-你有一个惯用的解决方案。空缓冲区是信息,因此框架实现返回它是合理的。不管怎样,任何其他方法都可以有效地执行与内部相同的操作 当我发现自己在使用一小群标准操作符时,我经常用一种更具解释性的扩展方法来包装它们。例如:
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);
}
}
为了“Rx-i-ness”,我将以下内容放入堆中
就个人而言,我认为詹姆斯的回答是足够的(在很多情况下可能更好)。唯一的区别(就输出而言)是缓冲区计时器仅在生成新项时启动。这就是为什么我们不需要过滤空缓冲区。尽管如此,这可能不是最有效的解决方案。这只是为了展示构图的力量
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());
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());