https://www.cnblogs.com/yangecnu/archive/2012/11/03/Introducting_ReactiveExtensions.html

前面我写过7篇文章粗略的介绍了一下Rx及其方方面面。Rx是一个好东西不然我也不会费这么大的力气来写这些东西。本文打算初略的讲一下传统异步编程方法的缺点,以及为啥Rx能够给异步编程带来新的体验。最后我听译了一篇关于Reactive Extension的非常好的一篇演讲,并制作了中英文字幕。希望大家看完这篇文章之后能够对Reactive Extension能够有比较深的印象,并在实际编程中遇到比较纠结的异步编程问题了能够想到Rx。

1. 传统异步编程存在的问题

异步编程比较困难,这一点老赵讲过很多次,在这里就我的理解有以下几点。

1.1 异步编程的方式太多,缺乏统一性

在.NET下面做异步编程其实有很多种选择的,如果基于事件的异步编程,经典的Begin/End异步方法对,以及针对以上两种存在的问题改进的CCRAsyncEnumerator,还有F#中的异步工作流,以及C#5.0中引入的Task和Async。方法多吧,这些方法在不同的场合具有不同的优缺点,但是要全部掌握对于一般的编程者来说比较难,缺乏一种统一的方式将这些异步编程方法统一的概况进来。

1.2 代码破碎,本地性不好

传统的异步编程方式迫使我们将逻辑分拆为两部分,而大家一般对线性的处理方式比较熟悉,相信大家比较熟悉基于事件的异步编程方式,一般地,你需要注册一个事件,这个事件处理方法通常和注册事件的代码不在同一个地方。在Begin/End异步方法对中,你也需要发起一个Begin异步方法,然后在其回调方法中,调用End方法。这通常会破坏代码的本地性,而且,如果你需要在Begin方法中传递一些参数的话,你还需要进行类型转换。在C#2.0中的闭包,匿名委托, C# 3.0中的lambda表达式,使得你可以在调用回调方法的地方传进去一个异步方法,这样在一定程度上减少了代码的破碎性,但是如果需要在异步方法中再次调用另外一个异步方法,那么代码就会比较难以维护了。再者对异步进行异常处理也是很麻烦的事情,你不得不在每一个地方都写上try catch。

1.3 异步方法难以进行组合

传统的异步编程也难以对方法进行组合,比如说要实现鼠标拖拽(Drag and Drop)这个功能,他涉及到多个事件,你需要记录很多个中间状态。而不像我们熟悉的LINQ那样对事件像对数据那样进行管道(Pineline)操作。

2. 什么是Rx

Rx提供了一种新的组织和协调异步事件的方式,极大的简化了代码的编写。Rx最显著的特性是使用可观察集合(Observable Collection)来达到集成异步(composing asynchronous)和基于事件(event-based)的编程的效果。Rx有一些几个特性,这一点在第一篇文章中也讲过:

  • 组合(Composing): Reactive Extension的首要目标之一就是将多种异步操作组合起来是的代码更加简单。要做到这一点,数据流必须定义清楚,这样代码就很清晰集中,使得异步操作代码异步处理代码不会充斥整个应用程序。
  • 异步(Asynchronous): 虽然Rx不仅仅能处理异步操作,但是使用Rx,大大简化了异步操作的实现,并且代码容易理解进而容易维护。
  • 基于事件(Event-based): Rx简化了传统的异步编程方式,在后面的文章中我们会看到拖放(drag and drop)模式的实现
  • Observable集合(Observable collections): Obervable Collection是Rx的核心,它是一种集合,集合的元素在第一次访问的时候可能还没有填充。它对与Rx的重要性类始于Enumerable集合对LINQ的重要性。

3. Rx给异步编程带来的新体验

3.1 统一了异步编程方式

对于基于事件的异步处理,我们可以调用Observable的FromEventPattern方法,如我们如果想监听某个对象的MouseDown事件, 使用Reactive Extension则可以像这样写:

IObservable<MouseEventArgs> mouseDown = Observable.FromEventPattern<MouseEventArgs>(this.myPictureBox, "MouseDown")
.Select(x =>x.EventArgs);

这样就将一个Image的MouseDown事件转换成了一个IObservable<MouseEventArgs>对象,然后我们再调用这个对象的Subscribe方法就可以进行事件注册,异常处理了。

同样,对于Begin/End异步方法对,也可以调用Observable的FromAsyncPattern的方法,这样你也就可以对该事件进行各种操作了。

WebRequest request = WebRequest.Create("www.baudu.com");
IObservable<WebResponse> webRequest = Observable.FromAsyncPattern<WebResponse>(request.BeginGetResponse, request.EndGetResponse)

3.2 良好的编程体验,代码本地性好

比如上面的例子,如果要异步请求并接着处理返回的请求,那么可以直接紧接着后面对该事件进行操作:

IObservable<String> result = webRequest.Select(res =>
{
using (var stream = res.GetResponseStream())
using (var sr = new StreamReader(stream))
{
return sr.ReadToEnd();
}
});

你可以就像写同步代码那样写异步代码,不需要强行的把异步方法写成一个主体一个回调,使得代码更加的紧凑和容易维护。

3.3 可以方便的对异步事件进行组合操作

Rx可以使得可以使用类似LINQ的语法对事件进行操作,比如现在要实现一个功能:在一个form上有一个textbox,现在要监听textbox的事件,并且要在用户输入停止后1秒钟才发起事件。如果您使用Rx,则可以写为:

// 取得TextBox控件的TextChanged事件
IObservable<String> textChanage=Observable.FromEventPattern<EventArgs>(textBox, "TextChanged")
.Select(_ => textBox.Text)
.Throttle(TimeSpan.FromSeconds(1)); // 等待1秒钟如果没有别的变化则使用最近的变化值

这个逻辑在实际中是很常见的,比如你需要根据用户的输入去进行webservice请求,如果用户输入的很快,且频繁更改输入值得话,如果不进行过滤,会进行很多不必要的请求。上面这段代码则很好的满足了要求,如果您用传统的基于事件的方式实现该逻辑的话,我想是非常麻烦的。

另外一个例子:比如说,你在form上有一个图片,你想实现Drag and Drop功能,如果使用Rx的话,代码如下:

var mouseDown = Observable.FromEventPattern<MouseEventArgs>(this.myPictureBox, "MouseDown")
.Select(x => x.EventArgs.GetPosition(this));
var mouseUp = Observable.FromEventPattern<MouseEventArgs>(this.myPictureBox, "MouseUp")
.Select(x => x.EventArgs.GetPosition(this));
var mouseMove = Observable.FromEventPattern<MouseEventArgs>(this.myPictureBox, "MouseMove")
.Select(x => x.EventArgs.GetPosition(this));
var dragandDrop = from down in mouseDown
from move in mouseMove.StartWith(down).TakeUntil(mouseUp)
select new
{
x = move.X - down.X,
y = move.Y - down.Y
}; dragandDrop.Subscribe(value =>
{
Canvas.SetLeft(this.myPictureBox, value.x);
Canvas.SetTop(this.myPictureBox, value.y);
});

可以看到代码风格是很线性化的,表面上没有回调,没有破碎的代码。可以很方便的对事件进行Pineline的操作。如果上面这部分逻辑您使用传统的方法实现的话,需要保存一系列状态,比如说什么时候开始,什么时候结束,开始和结束的位置等等,而且注册事件会使得代码比较散,可读性不如Rx的好。

4. 一些资源

为了帮助大家更好的了解Reactive Extension,我翻译了一篇在Channel9 上的演讲,DevCamp 2010 Keynote - Rx: Curing your asynchronous programming blues,个人觉得讲得非常好,对IObservable接口如何有IEnumerable演变,以及Rx如何帮助我们简化异步编程都有很详细的讲解。如果您感兴趣的话,可以直接在Channel9上看。当然,我花了很长时间听译并试着翻译了整个视频,有些地方听的不是很懂,不过应该不影响您理解,并制作了中英文的字幕,您可以到Channel9上下载高清视频,然后结合中英文字幕看,我也将该高清视频和字幕压制到一起并上传到youku上了,可能不会很清晰,还是强烈建议您Channel9下载下来看。

当然,除了这个非常好的介绍Rx的演讲之外,下面的一些英文资料也很有参考价值:

  1. Rx team blog http://blogs.msdn.com/b/rxteam/
  2. DevLab http://msdn.microsoft.com/en-us/data/gg577609
  3. Channel 9 http://channel9.msdn.com/Tags/Rx

如果您不喜欢看英文的话,下面的一些也很有参考价值:

1. CSDN上一位网友翻译的几篇日语文章介绍Rx的,个人觉得很好:

  1. Reactive Extensions (Rx) 入门(1) —— Reactive Extensions 概要
  2. Reactive Extensions (Rx) 入门(2) —— 安装 Reactive Extensions
  3. Reactive Extensions (Rx) 入门(3) —— Rx的事件编程①
  4. Reactive Extensions (Rx) 入门(4) —— Rx的事件编程②
  5. Reactive Extensions (Rx) 入门(5) —— Rx的事件编程③

2. 上面这些都很好,当然我之前也写了几篇介绍Rx,您要是觉得有时间的话,也不防瞧一瞧:

  1. Reactive Extensions入门(1):LINQ和Rx简单介绍
  2. Reactive Extensions入门(2):LINQ操作符
  3. Reactive Extensions入门(3):Rx操作符
  4. Reactive Extensions入门(4):Rx实战
  5. Reactive Extensions入门(5):ReactiveUI MVVM框架
  6. Reactive Extensions入门(6):使用Rx进行单元测试

最后,希望这些能够给您了解Reactive Extension及对异步编程新方式带来一定的帮助。

Reactive Extensions入门的更多相关文章

  1. Reactive Extensions介绍

    Reactive Extensions(Rx)是对LINQ的一种扩展,他的目标是对异步的集合进行操作,也就是说,集合中的元素是异步填充的,比如说从Web或者云端获取数据然后对集合进行填充.Rx起源于M ...

  2. Reactive Extensions(Rx) 学习

    Bruce Eckel(著有多部编程书籍)和Jonas Boner(Akka的缔造者和Typesafe的CTO)发表了“反应性宣言”,在其中尝试着定义什么是反应性应用. 这样的应用应该能够: 对事件做 ...

  3. 牛刀小试:使用Reactive Extensions(Rx),对短时间内多次发生的事件限流

    我之前有一篇文章介绍到了Reactive Extension这个组件,请参考下面的文章,其中有一些基本的概念和相关的链接 牛刀小试:使用Reactive Extensions(Rx),一行代码实现多线 ...

  4. Reactive Extensions(Rx)并发浅析

    Reactive Extensions(Rx)并发浅析 iSun Design & Code .Net并行编程 - Reactive Extensions(Rx)并发浅析 关于Reactive ...

  5. 使用Reactive Extensions(Rx),对短时间内多次发生的事件限流

    使用Reactive Extensions(Rx),对短时间内多次发生的事件限流 牛刀小试:使用Reactive Extensions(Rx),对短时间内多次发生的事件限流 我之前有一篇文章介绍到了R ...

  6. Reactive Extensions 相见恨晚的Rx.Net

    何为Reactive Extensions(Rx) Rx是一个遵循函数式编程的类库,它引用观察者以及迭代器设计模式对可观察对象产生的数据进行异步消费.使用Rx, 开发人员将使用LINQ运算符操作异步数 ...

  7. 2、Reactive Extensions for .NET(译)

    实验3-引入 .net 中的 events 到 Rx 目标:前面实验中的使用各种工厂构造方法创建一个 可观察序列是一个部分.把 .net 中现有的异步数据源进行关联 是更重要的事情.在这次实验中我们将 ...

  8. .Net并行编程 - Reactive Extensions(Rx)并发浅析

    关于Reactive Extensions(Rx) 关于Reactive Extensions(Rx),先来看一下来自微软的官方描述: The Reactive Extensions (Rx) is ...

  9. Rx (Reactive Extensions)

    The Reactive Extensions (Rx) is a library for composing asynchronous and event-based programs using ...

随机推荐

  1. 用bat写的一个小病毒

    最近看了一点bat的知识,具体说是看了一个博客:http://blog.csdn.net/qsyzb/article/details/17364581 用了三天才看完=.=,感觉作者整理整理可以把博客 ...

  2. 开发同事 Linux 实用基本操作

    Linux 有复杂的体系,有很多的命令,开发同事日常开发时,不像运维同事需要熟练使用很多命令. 下面记录下我在工作中,常用的基本命令: 一 日志查看 对于开发同事来说,日常工作中,Linux 中最常用 ...

  3. 760. Find Anagram Mappings乱序字符串的坐标位置

    [抄题]: Given two lists Aand B, and B is an anagram of A. B is an anagram of A means B is made by rand ...

  4. 前端学习01-06URL

    URL(Uniform Resource Locator) 统一资源定位 URL的基本组成:协议,主机名,端口号,资源名 例如: http://www.sina.com:80/index.html 相 ...

  5. netty中的PlatformDependent

    通过类名就知道这是一个平台有关的类,通过对该类的学习可以帮助我们实现一个跨平台的应用.但是有些方法放的实现不是很好,比如:isWindows0.通过File的separator就可以判断出来.没必要那 ...

  6. Djianggo 在windows中安装出现报错的解决方案

    Djianggo 在win7下 安装会报错 Traceback (most recent call last):File "setup.py", line 4, in <mo ...

  7. 【Arcgis for android】相关教程收集自网络

    请加入qq群:143501213 一起交流和学习 推荐博客: 张云飞VIR http://www.cnblogs.com/vir56k/tag/arcgis%20for%20android/ arcg ...

  8. java java 内部类

    java 内部类 一.java内部类: java内部类分为: 成员内部类.静态嵌套类.方法内部类.匿名内部类 . 内部类的共性: (1).内部类仍然是一个独立的类,在编译之后内部类会被编译成独立的.c ...

  9. metasploit 读书笔记-信息收集

    三、信息收集 被动信息收集 在不接触目标系统时进行的信息收集,包括使用工具Yeti、Whois (1)Whois msf > whois secmaniac.net (2)Netcraft:fi ...

  10. Eavl整理

    一. 严格模式 eval方法只能在非严格模式中进行使用,在use strict中是不允许使用这个方法的. 二. 用法 eval函数会接收一个参数obj,如果obj不是一个字符串,那么eval会直接返回 ...