简体   繁体   English

Rx:什么是订阅,订阅如何工作?

[英]Rx: What are subscriptions and how do subscriptions work?

I'm learning reactive extensions (rx) in .NET and I'm struggling a little bit with what a "subscription" really is and when it is used. 我正在学习.NET中的反应式扩展(rx),并且在“预订”的真正含义和使用时间方面有些挣扎。

Lets take some sample data, taken from this thread: 让我们从线程中获取一些样本数据:

using System;
using System.Reactive.Linq;
using System.Threading;

namespace ConsoleApp1
{
    class Program
    {
        class Result
        {
            public bool Flag { get; set; }
            public string Text { get; set; }
        }

        static void Main(string[] args)
        {               
            var source =
               Observable.Create<Result>(f =>
               {
                   Console.WriteLine("Start creating data!");

                   f.OnNext(new Result() { Text = "one", Flag = false });
                   Thread.Sleep(1000);
                   f.OnNext(new Result() { Text = "two", Flag = true });
                   Thread.Sleep(1000);
                   f.OnNext(new Result() { Text = "three", Flag = false });
                   Thread.Sleep(1000);
                   f.OnNext(new Result() { Text = "four", Flag = false });
                   Thread.Sleep(1000);
                   f.OnNext(new Result() { Text = "five", Flag = true });
                   Thread.Sleep(1000);
                   f.OnNext(new Result() { Text = "six", Flag = true });
                   Thread.Sleep(1000);
                   f.OnNext(new Result() { Text = "seven", Flag = true });
                   Thread.Sleep(1000);
                   f.OnNext(new Result() { Text = "eight", Flag = false });
                   Thread.Sleep(1000);
                   f.OnNext(new Result() { Text = "nine", Flag = true });
                   Thread.Sleep(1000);
                   f.OnNext(new Result() { Text = "ten", Flag = false });

                   return () => Console.WriteLine("Observer has unsubscribed");
               });
        }
    }
}

Beware of the line: 注意这一行:

 Console.WriteLine("Start creating data!");

Now, first I thought a subscription simply is used by using the .Subscribe operator. 现在,首先,我认为仅通过使用.Subscribe运算符即可使用订阅。 So an observer (eg the callback of the .Subscribe function) subscribes to an observable (the last return value of a chain of operators) like this (just as an example, the query doesn't have a real use): 因此,观察者(例如.Subscribe函数的回调)订阅了这样的可观察对象(一系列操作符的最后一个返回值)(仅作为示例,查询没有实际用途):

  source.Zip(source, (s1, s0) =>
     s0.Flag
     ? Observable.Return(s1)
     : Observable.Empty<Result>()).Merge().Subscribe(f => { Console.WriteLine(f.Text); });

Now I was expecting to get the "Start creating data!" 现在,我期望得到“开始创建数据!” output only once, since I was only using one subscription. 仅输出一次,因为我只使用一个订阅。 But in fact, I got it twice : 但实际上, 我两次得到了它

Start creating data!
Start creating data!
two
five
six
seven
nine

I was told that everytime I use an operator on source. 有人告诉我,每次我在source.上使用运算符时source. , a subscription is made. ,进行订阅。 But in this example I'm using source. 但是在此示例中,我使用的是source. only once and then a second time just as a parameter for the .Zip operator. 仅一次,然后第二次,作为.Zip运算符的参数。 Or is it because the source is passed to the .Zip function by value subscribed again? 还是因为源通过再次订阅的值传递到.Zip函数?

So my questions are: 所以我的问题是:

  1. What exactly is a "subscription" in terms of Rx? 就Rx而言,“订阅”到底是什么?
  2. Where / why exactly do the two subscriptions happen on my example? 在我的示例中,为什么两个订阅在哪里发生?

Btw. 顺便说一句。 I know I can prevent multiple subscriptions from happening by using the .Publish operator, but that isn't the scope of my questions. 我知道我可以通过使用.Publish运算符防止发生多个订阅,但这不是我的问题的范围。

In simple terms a Subscription just represents an Observable that has been subscribed to. 用简单的术语来说,订阅只是表示已订阅的Observable This process can happen either explicitly by using .Subscribe or implicitly by joining two or more Observables and then subscribing to the resulting chain. 通过使用.Subscribe可以显式地进行此过程,也可以通过加入两个或多个Observables隐式地进行订阅,然后订阅结果链。

In your case you are seeing both happen, once explicitly when you call Subscribe and one implicitly when you pass source to Zip , that is, there are two Subscriptions to the source Observable . 在你的情况,你所看到的都发生了,一旦明确,当你调用Subscribe和一个隐含当你通过source ,以Zip ,那就是,有两个Subscriptionssource Observable

Why is that important? 为什么这么重要? Because by default Observables are lazy, meaning that they will not begin processing until you subscribe to them (the product of that process being a Subscription ), by extension this means that any time you subscribe to the Observable it will effectively begin a new stream. 因为默认情况下Observables是懒惰的,这意味着直到您订阅他们(这个过程是一个的产品,他们将不会开始处理Subscription ),推而广之,这意味着您订阅随时 Observable它会有效地开始一个新的数据流。 This behavior can be overridden like you alluded to with Publish , but the default is for each Observable to be cold . 可以像您用Publish所提到的那样重写此行为,但是默认情况下,每个Observable的行为都是冷的

In your specific case, since you are passing the same Observable to Zip it needs to subscribe to it twice, since it will be zipping together events from the two passed streams. 在您的特定情况下,由于您要将相同的Observable传递给Zip因此需要订阅两次,因为它将把来自两个传递的流的事件压缩在一起。 The result is two subscriptions to the same Observable which each run independently of each other. 结果是同一个Observable两个订阅,每个订阅彼此独立运行。

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

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