rx被动扩展:如何让每个用户从一个可观察者获得一个不同的值(下一个)?

时间:2012-02-01 22:24:24

标签: system.reactive async-ctp

使用反应式扩展,很容易为同一个观察者订阅2次。 当observable中有新值时,将使用相同的值调用这两个订阅者。

有没有办法让每个订阅者从这个可观察的角度获得不同的值(下一个)?

我所追求的是什么:
源序列:[1,2,3,4,5,...](无限)
消息来源不断以不明的速度添加新物品 我正在尝试使用N个订阅者为每个项目执行lenghty异步操作。

第一位订户:1,2,4,...
第二位订户:3,5,...
...

第一位订户:1,3,...
第二位订户:2,4,5,...
...

第一位订户:1,3,5,...
第二位订户:2,4,6,......

2 个答案:

答案 0 :(得分:1)

我同意阿斯蒂。

您可以使用Rx填充队列(阻止集合),然后让竞争消费者从队列中读取。这样一来,如果一个进程由于某种原因更快,它可能会在另一个消费者仍然忙碌之前可能会在另一个消费者之前获取下一个项目。

但是,如果你想这样做,反对好建议:),那么你可以使用Select运算符来为你提供每个元素的索引。然后,您可以将其传递给订阅者,他们可以适应模数。 (Yuck!Leaky抽象,幻数,可能阻塞,对源序列的潜在副作用等)

var source = Obserservable.Interval(1.Seconds())
  .Select((i,element)=>{new Index=i, Element=element});

var subscription1 = source.Where(x=>x.Index%2==0).Subscribe(x=>DoWithThing1(x.Element));
var subscription2 = source.Where(x=>x.Index%2==1).Subscribe(x=>DoWithThing2(x.Element));

还要记住,OnNext处理程序在阻塞时所做的工作仍然会阻止它所在的调度程序。这可能会影响您的源/制作人的速度。阿斯蒂答案的另一个原因是更好的选择。

询问是否不清楚: - )

答案 1 :(得分:1)

怎么样:

IObservable<TRet> SomeLengthyOperation(T input) 
{
    return Observable.Defer(() => Observable.Start(() => {
        return someCalculatedValueThatTookALongTime;
    }, Scheduler.TaskPoolScheduler));
}

someObservableSource
    .SelectMany(x => SomeLengthyOperation(input))
    .Subscribe(x => Console.WriteLine("The result was {0}", x);

您甚至可以限制并发操作的数量:

someObservableSource
    .Select(x => SomeLengthyOperation(input))
    .Merge(4 /* at a time */)
    .Subscribe(x => Console.WriteLine("The result was {0}", x);

Merge(4)的工作非常重要,SomeLengthyOperation返回的Observable是 Cold Observable,这就是Defer在这里做的事情 - 它使得Observable.Start不会发生直到有人订阅。