Contents
  1. 1. 何为响应式编程
  2. 2. 交互式编程与响应式编程
  3. 3. 响应式系统模型
    1. 3.1. Actor模型
    2. 3.2. 函数响应式编程(functional reactive programming,FRP)
    3. 3.3. 响应式扩展(reactive extensions,Rx)
    4. 3.4. 小结
  4. 4. 响应式系统须遵循的特征
    1. 4.1. 消息传递或事件传递
    2. 4.2. 可灵活伸缩
    3. 4.3. 容错可恢复
    4. 4.4. 响应式
  5. 5. 异步程序处理的思维转变
  6. 6. 总结

何为响应式编程

响应式编程是一种面向数据流和变化传播的编程范式,数据更新是相关联的。 这意味着可以在编程语言中很方便地表达静态或动态的数据流,而相关的计算模型会自动将变化的值通过数据流进行传播。
以响应式编程方式进行思考,意味着要放弃命令式且带状态的编程习惯,并且强迫你的大脑以一种不同的方式去工作。
响应式编程提高了代码的抽象层级,所以你可以只关注定义了业务逻辑的那些相互依赖的事件,而非纠缠于大量的实现细节。它可以简化项目,特别是处理嵌套回调的异步事件、复杂的列表过滤和变换,或时间相关问题。

交互式编程与响应式编程

平时我们使用最多的便是“交互式(Interactive)”的编程方式,采用的是组件之间的相互调用来表现逻辑。例如,对象A向对象B请求数据并等待返回,待对象B完成并返还数据之后A才继续进行后面的操作。
响应式编程是一种基于“改变”的编程方式。例如在交互式编程中,A = B + C这样的表达式意味着将B与C之和赋给A,而此后B与C的改变都与A无关。而在响应式编程中,A会去“响应”B或C的变化,即一旦B或C改变之后,A的值也会随之变化。响应式编程的一个典型应用便是GoF23中的观察者模式。

响应式系统模型

Actor模型

Actor模型=数据+行为+消息。Actor模型内部的状态由自己的行为维护,外部线程不能直接调用对象的行为,必须通过消息才能激发行为,这样就保证Actor内部数据只有被自己修改。
Actor是一个个独立的实体,他们之间是毫无关联的。但是,他们可以通过消息来通信。一个Actor收到其他Actor的信息后,它可以根据需要作出各种相应。Actor的常见应用模式是处理大规模并发输入流:将具体工作分类给异步的工作节点,之后返回工作节点计算的结果。
Actor模型实际上并不是纯正的函数式编程模型。Receive方法返回Unit类型,这意味着在该方法中,所有事情都是通过副作用完成的。再者,只要需要,Actor模型便会允许使用可变状态,但这里要遵守一个规则,将状态封装在某个actor中,并确保所有状态的响应操作是线程安全的。
综上,Actor模型是处理大规模、高度可用、事件驱动应用程序的更为通用的方法。

函数响应式编程(functional reactive programming,FRP)

在函数响应式编程模型中,基于时间的状态需要通过某一系统传播到需要使用这些状态的代码中。当FRP模型中的某一状态发生变化时,你并不需要手动地对依赖这些变化的变量进行更新,与之相反,FRP会使用声明的方式描述数据元素之间的依赖关系,而FRP运行时则会负责状态的传播。因此,用户使用函数式声明语句和组合语法编写代码。

FRP基本上就是面向异步事件流的编程了,这个异步事件流(Stream)是一个按时间排序的事件序列。Stream是不可变的,任何操作都返回新的Stream,且它是一个Monad。

响应式扩展(reactive extensions,Rx)

响应式扩展这个概念最早出现在.net社区的Rx.net,一个提供处理异步事件的程序库,其核心概念是Observable,表示有限或者无限多个现在或者将来到达的事件。Observable提供了onNext,onError,onCompleted供开发者定制新元素到达,出现错误,或者流结束时的程序的行为。并提供了List上类似的操作,如map,filter,reduce,大大降低了异步事件编程的复杂度。
因为这些概念是如此的强大,以至于很多编程语言,如java,ruby,javascript很快就有了各自的reactvie extension。

Rx模型中的可观察序列代表事件流或其他数据源。通过将可观察序列与LINQ(language-integrated query,语言集成查询)库提供的查询操作符(组合器)拼接起来,Rx组成了异步程序。

小结

Actor、FRP以及Rx都是基于事件的系统模型。FRP和Rx模型更像是一个处理各类事件流的管道系统,而Actor模型则像是一个包装各个组件进行交互的网络系统。尽管略有差异,但是这些模型都能够通过多种方式进行扩展。有一点可以断言,Actor模型健壮的错误处理策略,使得它对响应性提供的支持称为最强的支持。值得一提的是,尽管这些模型提高系统响应度的方式不同,但所有模型都致力于最大程度地减少阻塞。

响应式系统须遵循的特征

所有可伸缩、可恢复的响应式程序都应遵循这些特征:

  • react to events (events-driven)
  • react to load (scalable)
  • react to failures (resilient)
  • react to users (resonsive)

消息传递或事件传递

响应式系统必须能对消息或事件进行响应,也可以称作是事件驱动(event-driven)的,这是最基本的要求。
在传统的多线程系统中,多个线程通过共享同步状态进行通信,这种方式是强耦合的,难以进行组合;而响应式系统由弱耦合的事件句柄构成,事件传递是异步高效的,不会导致阻塞。

可灵活伸缩

为了能够满足处理要求,响应式系统是可伸缩的系统。这意味着该系统能够通过向上扩展(scale up)的方式利用多核系统进行并行计算,通过向外扩展(scale out)的方式利用多个服务器节点。对于向上扩展而言,最重要的是减少可变状态的共享;而对于向外扩展而言,最重要的是要做到位置透明性(location transparency)来保证不同机器上的程序具有同样的功能,通过弹性(resilience)来处理不同服务器节点的错误和崩溃。
理想状态下,为了能够动态响应不停变化的处理需求,系统应该根据当前需求动态的执行向上扩展,这种调整既包括增加处理资源,也包括自动回收资源。用这种方法,我们需要花费大量的精力才能对那些需要维护重要状态信息的服务进行向外扩展,而且这类系统也很难对状态信息进行“分片”和可靠的复制。

容错可恢复

随着系统不断变大,那些不常见的事件也会越来越频繁地出现在系统中。因此,错误(如异常这样的程序错误,宕机这样的硬件错误,网络连接这样的通信错误)也是需要考虑的头等大事。构造响应式系统时,必须在系统设计之初就考虑错误处理的问题,不断进行改造,以便能够在出现错误时优雅地恢复系统。所以常常需要弱耦合,对状态的封装和通用的监督系统的设计。

响应式

响应式系统需要能够随时对服务请求进行响应,即使系统出现了错误的组件或是经历非常高的流量峰值,响应式也需要通过优雅降级的方式继续响应用户的请求。其需要建立在事件驱动、可扩展性和弹性架构这些属性之上。

异步程序处理的思维转变

在异步事件处理程序中(比如GUI编程),常常通过回调函数来处理事件,这是建立在观察者模式的一种处理方式。这种方式有几点问题:

  1. 回调函数常常带有副作用,会导致回调函数和监听对象共享的变量(可变状态)发生改变
  2. 难以通过简单的监听对象实现更高的抽象,事件句柄很难进行组合
  3. 导致了“回调地狱(call-back hell)”,回调函数构成的网络难以理解和追踪

为了解决传统情况带来的困境,响应式编程从函数式编程之中借鉴了基本的元素和思想,得到了可组合的事件抽象(composable event abstractions)

  1. 事件是一等成员
  2. 事件常常表现为消息
  3. 事件处理程序同样是一等的
  4. 复杂的处理程序(complex handlers)可以由基础的程序组合而成

要学习响应式编程,我们首先要理解monad这个函数式设计模式,由于响应式编程并不是纯函数式的,故我们还需要将纯函数式编程和现实世界(包含了可变状态和非确定性计算)结合起来。有了上面两点做基础,我们还要学习使用future对事件进行抽象,使用observable对事件流进行抽象。最后再学习基于消息传递的系统架构——actor模型,以至于构建分布式的actor系统。

总结

本节中给出了响应式编程的基本概念,讨论了响应式系统模型和所遵循的特征。由于该方面的相关资料较为混乱,使得我在学习过程中难以把握一些概念的定界,待日后勤加实践,从Scala的并发系统和akka框架入手,加深对响应式编程的理解。

转载请注明作者Jason Ding及其出处
jasonding.top
Github博客主页(http://blog.jasonding.top/)
CSDN博客(http://blog.csdn.net/jasonding1354)
简书主页(http://www.jianshu.com/users/2bd9b48f6ea8/latest_articles)
Google搜索jasonding1354进入我的博客主页

Contents
  1. 1. 何为响应式编程
  2. 2. 交互式编程与响应式编程
  3. 3. 响应式系统模型
    1. 3.1. Actor模型
    2. 3.2. 函数响应式编程(functional reactive programming,FRP)
    3. 3.3. 响应式扩展(reactive extensions,Rx)
    4. 3.4. 小结
  4. 4. 响应式系统须遵循的特征
    1. 4.1. 消息传递或事件传递
    2. 4.2. 可灵活伸缩
    3. 4.3. 容错可恢复
    4. 4.4. 响应式
  5. 5. 异步程序处理的思维转变
  6. 6. 总结