简体   繁体   English

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

[英]Why subscribing an observable in RX.NET by Latest only accepts 1 subscriber?

My goal is to have two subscribers from an observable but I am only interested in the Latest item in the event stream. 我的目标是从观察者中获得两个订阅者,但我只对事件流中的最新项目感兴趣。 I want others to be discarded. 我希望别人被抛弃。 Consider this like a stock price screen that updates every 1 second and disregarding any intermediate values. 将此视为股票价格屏幕,每1秒更新一次并忽略任何中间值。 Here's my code: 这是我的代码:

    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);
        });

However as a result of above code, despite I attached two events (it doesn't matter even if you use the subscribe notation either) Only the first subscription is invoked periodically. 但是由于上面的代码,尽管我附加了两个事件(即使你使用订阅符号也没关系)只定期调用第一个订阅。 Second one doesn't run at all. 第二个根本不运行。 Why is that so ? 为什么会这样 ?

First I think your requirement is one of the following: 首先,我认为您的要求是以下之一:

  1. You want to only get future values 您只想获得未来的价值
  2. or you want to get the most recent value (if any) and any future values 或者您想获得最新值(如果有)和任何未来值
  3. or you only want the most recent value (if any) 或者你只想要最新的价值(如果有的话)
  4. or you only want to sample the ticks and get the value at each second 或者你只想抽取刻度并获得每秒的值
  5. or you have a slow consumer and you need perform load shedding (like in a GUI) 或者你的消费者很慢,你需要执行减载(如在GUI中)

The code for 1) 1)的代码

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

The code for 2) 2)的代码

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

The code for 3) 3)的代码

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

The code for 4) can be this, but there are subtle behaviors around what you consider a window. 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());  

The code for 5) can be found on James World's blog http://www.zerobugbuild.com/?p=192 and is quite common in many banking applications in London. 5)的代码可以在James World的博客http://www.zerobugbuild.com/?p=192上找到,并且在伦敦的许多银行应用程序中很常见。

I don't think you understand what .Latest() does. 我不认为你明白什么.Latest()的确如此。

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

The enumerable sequence that returns the last sampled element upon each iteration and subsequently blocks until the next element in the observable source sequence becomes available. 可枚举序列,在每次迭代时返回最后一个采样元素,然后阻塞,直到可观察源序列中的下一个元素变为可用。

Note that it blocks waiting for the next element from the observable. 请注意,它会阻止等待来自observable的下一个元素。

So when you turned the IObservable<> into an IEnumerable<> using .Latest() you then had to use .ToObservable() to turn it back into an IObservable<> to be able to call .ToEvent() . 因此,当您使用.Latest()IObservable<>转换为IEnumerable<>您必须使用.ToObservable()将其转换回IObservable<>以便能够调用.ToEvent() That's where it fell over. 这就是它倒下的地方。

The problem with this code is that you're creating code that blocks. 此代码的问题在于您正在创建阻止的代码。

If you just do it this, it works: 如果你这样做,它的工作原理:

var ob = Observable.Interval(TimeSpan.FromMilliseconds(100)).ToEvent();

There's no need to call .Latest() as you're always getting the latest value from an observable. 没有必要调用.Latest()因为你总是从一个observable获得最新的值。 You can never get an earlier value. 你永远无法获得更早的价值。 It's an observable, not a time machine. 这是一个可观察的,而不是时间机器。

What I also don't understand is why you are calling .ToEvent() in any case. 我也不明白为什么你在任何情况下调用.ToEvent() what's the need? 有什么需要?

Just do this: 这样做:

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);
});

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM