Reactive Extensions中的嵌套订阅

时间:2012-09-09 00:36:14

标签: c# system.reactive

在特定线程上让观察者正常工作时遇到问题。

Subject<bool> subjEvent = new Subject<bool>();
Subject<int> subjValue = new Subject<int>();

IScheduler sched = new EventLoopScheduler(ts => new Thread(ts));

subjEvent.ObserveOn(sched).Subscribe(
    r =>
        {
            if(r)
            {
                Console.WriteLine("Connected On: \t{0}", Thread.CurrentThread.ManagedThreadId);

                subjValue.ObserveOn(sched).Subscribe(
                    x => Console.WriteLine("Recieved On: \t{0}", Thread.CurrentThread.ManagedThreadId));
            }else{
                Console.WriteLine("Disconnect On: \t{0}", Thread.CurrentThread.ManagedThreadId);
            }
        }
    );

subjEvent.OnNext(true);
for(int i=0; i< 10; i++)
{
    subjValue.OnNext(i);
}
subjEvent.OnNext(false);
subjValue.OnCompleted();
subjEvent.OnCompleted();

这个想法是在可用时订阅某些内容,然后取消订阅/重新订阅事件。现在我需要观察一个特定的(读取相同的)线程,以及确保正确的排序,我有一个EventLoopScheduler。

问题是我从价值订阅中得不到任何东西。

现在,如果我将Thread.Sleep(10)添加到生成循环(OnNext之后),它可以正常工作。所以我对我做错了什么感到困惑,并且非常感谢帮助/建议。

2 个答案:

答案 0 :(得分:3)

虽然这无助于直接回答你的问题 - 我认为Asti做得很好 - 我想我会发布这段代码来帮助你写出你的问题。

你应该非常努力不要订阅你的观察者,直到你必须这样做。当您执行OnNext处理程序中的代码时,需要尽可能小。

尝试此版本的查询:

var query =
    from b in subjEvent.Do(x =>
        Console.WriteLine("{0}onnected On: \t{1}",
            x ? "C" : "Disc",
            Thread.CurrentThread.ManagedThreadId))
    select b ? subjValue : Observable.Empty<int>();

query.Switch().Subscribe(x =>
    Console.WriteLine("Recieved On: \t{0}",
        Thread.CurrentThread.ManagedThreadId));

除了事件循环调度程序的问题,此代码与您的代码相同,但它只有一个订阅,并且它在该订阅中执行的工作量最小。我希望这会有所帮助。

答案 1 :(得分:2)

这虽然是非确定性的预期行为。 问题是第二个订阅是在EventLoopScheduler中设置的。设置订阅以供调度程序观察需要一些时间。但是它的通知已经在主线程中进行了。在设置订阅时,循环将完成执行。

要查看此情况,请从活动主题中移除ObserveOn。这将强制在继续使用值通知第二个主题之前设置订阅。您还可以在OnNext(true)之后留出一些时间来允许它连接订阅。