我有无限的物体流。我的要求是应该同步处理具有相同密钥的可观察流中的每个项目,并且具有不同密钥的所有其他项目可能/应该并行处理。最简单的方法(如大多数地方所述)是使用GroupByUntil
运算符:
var results = observableStream
.GroupByUntil(item => item.Id, group =>
group.Throttle(TimeSpan.FromSeconds(30), scheduler))
.SelectMany(group =>
group
.ObserveOn(scheduler)
.Select(item => ProcessItem(item)));
var disposable = results.Subscribe(result => SaveResults(result));
代码运行良好,直到我可以保证ProcessItem(item)
的执行时间少于30秒。否则group.Throttle(TimeSpan.FromSeconds(30), scheduler)
将关闭群组的流,新项目到达并开始处理新线程的概率非常高。
所以基本上我需要以某种方式知道我的线程已经完成了处理具有特定密钥的所有项目,我需要在durationSelector
GroupByUntil
运算符参数内通知它。
关于如何实现这一目标的任何想法?提前谢谢。
答案 0 :(得分:2)
这与此问题非常相似:A way to push buffered events in even intervals。
形成该问题的答案,有一个运营商Drain
:
public static class ObservableDrainExtensions
{
public static IObservable<TOut> Drain<TSource, TOut>(this IObservable<TSource> source,
Func<TSource, IObservable<TOut>> selector)
{
return Observable.Defer(() =>
{
BehaviorSubject<Unit> queue = new BehaviorSubject<Unit>(new Unit());
return source
.Zip(queue, (v, q) => v)
.SelectMany(v => selector(v)
.Do(_ => { }, () => queue.OnNext(new Unit()))
);
});
}
}
鉴于该操作员,您的问题变得非常简单:
var results = observableStream
.GroupBy(item => item.Id)
.SelectMany(group =>
group
.ObserveOn(scheduler)
.Drain(item => ProcessItem(item)));
var disposable = results.Subscribe(result => SaveResults(result));
给定一个看起来像A1,A2,B1,A3,B2,C1,B3,C2的流,GroupBy
按ID分隔流:
A: A1, A2, A3
B: B1, B2, B3
C: C1, C2
...而Drain
确保对于给定子流中的项目,它们以串行方式运行,而不是并行运行。