为什么在RX.NET中订阅RX.NET中的observable只接受1个订阅者?

时间:2016-02-09 07:25:21

标签: c# system.reactive

我的目标是从观察中获得两个订阅者,但我只对事件流中的最新项目感兴趣。我希望别人被抛弃。将此视为股票价格屏幕,每1秒更新一次并忽略任何中间值。 这是我的代码:

    var ob = Observable.Interval(TimeSpan.FromMilliseconds(100)) // fast event source
        .Latest().ToObservable().ToEvent();

    ob.OnNext += (l =>
                      {
                          Console.WriteLine(Thread.CurrentThread.ManagedThreadId);
                          Thread.Sleep(1000); // slow processing of events
                          Console.WriteLine("Latest: " + l);
                                                    });

    ob.OnNext += (l =>
        {
            Console.WriteLine(Thread.CurrentThread.ManagedThreadId);
            Thread.Sleep(1000); // slow processing of events
            Console.WriteLine("Latest1: " + l);
            //  subject.OnNext(l);
        });

然而,作为上述代码的结果,尽管我附加了两个事件(即使您使用订阅符号也无关紧要)仅定期调用第一个订阅。第二个根本不运行。为什么会这样?

2 个答案:

答案 0 :(得分:2)

首先,我认为您的要求是以下之一:

  1. 您只想获得未来的价值
  2. 或者您想获取最新值(如果有)和任何未来值
  3. 或者您只想要最近的值(如果有的话)
  4. 或者您只想抽取刻度并获取每秒的值
  5. 或者你的消费者很慢,你需要执行减载(如在GUI中)
  6. 1)的代码

    var ob = Observable.Interval(TimeSpan.FromMilliseconds(1000)) // fast event source
        .Publish();
    ob.Connect();
    

    2)的代码

    var ob = Observable.Interval(TimeSpan.FromMilliseconds(1000)) // fast event source
        .Replay(1);
    ob.Connect();    
    

    3)的代码

    var ob = Observable.Interval(TimeSpan.FromMilliseconds(1000)) // fast event source
        .Replay(1);
    ob.Connect();  
    var latest = ob.Take(1); 
    

    4)的代码可以是这样,但是你认为窗口有一些微妙的行为。

    var ob = Observable.Interval(TimeSpan.FromMilliseconds(200)) // fast event source
        .Replay(1);
    //Connect the hot observable
    ob.Connect();
    
    var bufferedSource = ob.Buffer(TimeSpan.FromSeconds(1))
        .Where(buffer => buffer.Any())
        .Select(buffer => buffer.Last());  
    

    5)的代码可以在James World的博客http://www.zerobugbuild.com/?p=192上找到,并且在伦敦的许多银行应用程序中很常见。

答案 1 :(得分:1)

我认为您不了解.Latest()的作用。

public static IEnumerable<TSource> Latest<TSource>(
    this IObservable<TSource> source
)
  

可枚举序列,在每次迭代时返回最后一个采样元素,然后阻塞,直到可观察源序列中的下一个元素变为可用。

请注意,它阻止等待来自observable的下一个元素。

因此,当您使用IObservable<>IEnumerable<>变为.Latest()时,您必须使用.ToObservable()将其重新设置为IObservable<>才能使用.ToEvent()致电var ob = Observable.Interval(TimeSpan.FromMilliseconds(100)).ToEvent(); 。这就是它倒下的地方。

此代码的问题在于您正在创建阻止的代码。

如果你这样做,那就有效:

.Latest()

无需调用.ToEvent(),因为您始终从可观察的内容中获取最新值。你永远无法获得更早的价值。这是一个可观察的,而不是时间机器。

我也不明白为什么你在任何情况下都在呼叫var ob = Observable.Interval(TimeSpan.FromMilliseconds(100)); ob.Subscribe(l => { Console.WriteLine(Thread.CurrentThread.ManagedThreadId); Thread.Sleep(1000); // slow processing of events Console.WriteLine("Latest: " + l); }); ob.Subscribe(l => { Console.WriteLine(Thread.CurrentThread.ManagedThreadId); Thread.Sleep(1000); // slow processing of events Console.WriteLine("Latest1: " + l); }); 。有什么需要?

这样做:

PictureBox