我是Rx的新手.我可以看到使用Hot Observables的一些真正的好处,但是我最近被问到一个关于冷可观察和等效可枚举之间的区别的问题(参见下面的代码片段)…
var resRx = Observable.Range(1,10); var resOb = Enumerable.Range(1,10);
任何人都可以非常简单地解释两者之间的区别是什么,以及从冷可观察者到可枚举者可以得到什么好处.
解决方法
两者之间存在一些差异.
谁控制’枚举’
对于可观察(热或冷),可观察的是确定何时以及在什么线程上返回值.另一方面,可枚举在您请求时获取每个值,并在请求枚举的线程上处理.
代码流程
处理枚举通常在每个循环中完成(或偶尔获取枚举数并使用while循环).您的代码通常会在继续之前处理所有值. Observable需要回调.阻止进一步执行代码(比如不要退出控制台应用程序)需要额外的代码.对于可观察对象有一些阻塞运算符,例如First,但它们是例外而不是正常使用的规则.
以这个简单的示例程序为例.使用可枚举的值,所有值都会在继续下一部分之前编写.但是,不能保证可以观察到可观察值.在程序终止之前写入多少个值几乎就是竞争条件.
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 }
异步进程
就像你必须编写额外的代码来阻止和等待一个observable一样,编写一个使用异步进程的IEnumerable需要一些额外的工作.这是两者之间真正发挥作用的地方.
例如,在我目前正在处理的应用程序中,我需要搜索可能连接到串行端口的设备. IObservable非常适合这种情况,因为它允许我进行回调并在我找到它时通知应用程序,而不必阻塞和操作完成.这个observable有资格作为cold observable,因为除非有订阅者,否则它不会推送数据,并且每个订阅都会获得所有结果. (与典型的冷观察不同,我在订阅之前开始工作,但没有数据丢失,因为它被缓冲到重放主题中.)但是,由于异步,将它转换为Enumerable对我来说没有多大意义.性质.