简体   繁体   English

RX中的冷可观察性与正常可数的差异

[英]Difference between cold observable in RX and normal Enumerable

I am new to Rx. 我是Rx的新手。 I can see some real benefits of using Hot Observables, however I was recently asked the question on what the difference was between a cold observable and an equivalent enumerable (see code snippet below)... 我可以看到使用Hot Observables的一些真正的好处,但是我最近被问到一个关于冷可观察和等效可枚举之间的区别的问题(参见下面的代码片段)...

    var resRx = Observable.Range(1, 10);
    var resOb = Enumerable.Range(1, 10);

Can anyone explain very simply what the difference is between the two and what benefit I would get from the cold observable vs the enumerable. 任何人都可以非常简单地解释两者之间的区别是什么,以及从冷可观察者到可枚举者可以得到什么好处。

There are several differences between the two. 两者之间存在一些差异。

Who controls the 'enumeration' 谁控制'枚举'

With the observable (hot or cold), it is the observable that determines when and on what thread the values are returned. 对于可观察(热或冷),可观察的是确定何时以及在什么线程上返回值。 An enumerable on the other hand gets each value when you request it and is processed on the thread requesting the enumeration. 另一方面,可枚举在您请求时获取每个值,并在请求枚举的线程上处理。

Code Flow 代码流程

Processing enumerables is typically done in a for each loop (or occasionally getting the enumerator and using a while loop). 处理枚举通常在每个循环中完成(或偶尔获取枚举数并使用while循环)。 Your code will typically process all values before continuing. 您的代码通常会在继续之前处理所有值。 Observables require a callback. Observable需要回调。 Blocking further execution of your code (say to keep from exiting a console app) requires extra code on your part. 阻止进一步执行代码(比如不要退出控制台应用程序)需要额外的代码。 There are some blocking operators for observables, such as First , but they are the exception rather than the rule for normal usage. 对于可观察对象有一些阻塞运算符,例如First ,但它们是例外而不是正常使用的规则。

Take this trivial sample program as an example. 以这个简单的示例程序为例。 With the enumerable, all the values get written before continuing on to the next part. 使用可枚举的值,所有值都会在继续下一部分之前编写。 The values from the observable, however, are not guaranteed to ever be written. 但是,不能保证可以观察到可观察值。 How many values gets written before the program terminates is pretty much a race condition. 在程序终止之前写入多少个值几乎就是竞争条件。

static void Main(string[] args)
{
    var xs = Enumerable.Range(1, 10);
    foreach (var x in xs)
    {
        Console.WriteLine(x);
    }
    //at this point, all values have been written

    var ys = Observable.Range(1, 10);
    ys.Subscribe(y => Console.WriteLine(y));
    //at this point, no values have been written (in general)

    //either add a Console.ReadKey or some sort of wait handle that
    //is set in the OnCompleted of the observer to get values
}

Asynchronous processes 异步进程

Much like you have to write extra code to block and wait for an observable, writing an IEnumerable that uses an asynchronous process requires some extra work. 就像你必须编写额外的代码来阻塞和等待一个observable一样,编写一个使用异步进程的IEnumerable需要一些额外的工作。 Here is where the difference between the two really comes into play. 这是两者之间真正发挥作用的地方。

For example, in an application I am currently working on, I need to search for devices that may be attached to a serial port. 例如,在我目前正在处理的应用程序中,我需要搜索可能连接到串行端口的设备。 An IObservable is a good fit for this because it allows me to take a callback and notify the application for each device whenever I find it without having to block and when the operation is complete. IObservable非常适合这种情况,因为它允许我进行回调并在我找到它时通知应用程序,而不必阻塞和操作完成。 This observable qualifies as a cold observable because it will not push data out unless there is a subscriber, and each subscription gets all the results. 这个observable有资格作为cold observable,因为除非有订阅者,否则它不会推送数据,并且每个订阅都会获得所有结果。 (Unlike the typical cold observable, I start the work before a subscription, but no data is lost because it gets buffered into a replay subject.) However, it would not make much sense to me to convert it to an Enumerable because of the asynchronous nature. (与典型的冷可观察性不同,我在订阅之前开始工作,但没有数据丢失,因为它被缓冲到重放主题中。)但是,由于异步,将它转换为Enumerable对我来说没有多大意义。性质。

Almost all Enumerables that you are used to are "Cold" Enumerables? 你习惯使用的几乎所有Enumerables都是“冷”枚举? Why? 为什么? Because if you were to ForEach over the Enumerable.Range twice, you'd get 2x the numbers. 因为如果你在Enumerable.Range上两次使用ForEach,那么你得到2倍的数字。

If Enumerable.Range were a Hot Enumerable, it would only give you the list once and the 2nd ForEach would just be empty. 如果Enumerable.Range是Hot Enumerable,它只会给你一次列表而第二个ForEach只是空的。

For Rx, a Cold Observable means that every time you call Subscribe (the equivalent of ForEach in Rx), you'll receive a new list of stuff. 对于Rx,Cold Observable意味着每次调用Subscribe(相当于Rx中的ForEach)时,您都会收到一个新的东西列表。 Hot Observables like FromEvent aren't going to give you a new stream of events every time you Subscribe, it's just going to be another connection to the same event stream. 像FromEvent这样的Hot Observable不会在每次订阅时为您提供新的事件流,它只是与同一事件流的另一个连接。

What's the advantage of Rx here though? 这里Rx有什么优势? Being able to convert that range into async requests: 能够将该范围转换为异步请求:

IObservable<Image> fetchImageByIndex(int imageIndexOnSite);

Observable.Range(0, 10)
    .SelectMany(x => fetchImageByIndex(x)) 
    .Subscribe(image => saveImageToDisk(image));

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

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