使用SubscribeOn时,避免在Rx中重叠OnNext调用(Scheduler.TaskPool)

时间:2012-02-06 12:51:00

标签: c# system.reactive

我有一些使用Rx的代码,从多个线程调用:

subject.OnNext(value); // where subject is Subject<T>

我希望在后台处理这些值,因此我的订阅是

subscription = subject.ObserveOn(Scheduler.TaskPool).Subscribe(value =>
{
    // use value
});

我并不关心哪些线程处理来自Observable的值,只要将工作放入TaskPool并且不阻止当前线程。但是,我在OnNext委托中使用'value'并不是线程安全的。目前,如果很多值正在通过Observable,我正在调用我的OnNext处理程序。

我可以为我的OnNext委托添加一个锁,但这不像Rx的做法。当我有多个线程调用subject.OnNext(value);时,确保我一次只调用一次OnNext处理程序的最佳方法是什么?

4 个答案:

答案 0 :(得分:12)

来自MSDN上的Using Subjects

  

默认情况下,主题不会执行任何同步   线程。 [...]但是,如果你想   您可以使用调度程序将调用同步到观察者   使用Synchronize方法。

所以你应该像布兰登在评论中所说的那样同步主题并将其交给你的制作人线程。 e.g。

var syncSubject = Subject.Synchronize(subject);

// syncSubject.OnNext(value) can be used from multiple threads

subscription = syncSubject.ObserveOn(TaskPoolScheduler.Default).Subscribe(value =>
{
    // use value
});

答案 1 :(得分:6)

我认为您正在寻找.Synchronize()扩展方法。为了在最近的版本(2011年末)中获得性能改进,他们Rx团队放宽了关于可观察序列生成器的顺序性质的假设。然而,你似乎打破了这些假设(并不是坏事),但是为了让Rx像用户期望的那样重新播放,你应该同步序列以确保它再次顺序。

答案 2 :(得分:1)

这里有更多解释为什么要使用Synchronize(第二段)。 从另一方面,如果你在代码中主动使用锁定,则Synchronize可能会参与死锁,至少我目睹了这种情况。

答案 3 :(得分:0)

您可以尝试实现自己的IObserver,它将在其OnNext方法中应用锁定。只是一个简单的装饰器:应用一个锁,调用内部OnNext,删除锁。

然后你可以在IObservable上实现一个扩展方法,比如.AsThreadSafe()。