漫谈响应式编程
Posted 河北索维科技
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了漫谈响应式编程相关的知识,希望对你有一定的参考价值。
很多开发人员,不论是前端、后端还是移动端都会从各种途径中获知响应式编程这个概念,因为很多框架都开始宣称支持响应式开发。在我们意识到这一点时,大家都会尝试搜索各种文章资料想了解响应式编程到底是什么,可是互联网资料真的是太“丰富”了,丰富到你看了看了半天,可能还摸不清头脑,因为响应式理论是从问题的底层重建了整个概念体系,一个概念牵扯出另一个概念,然后概念越来越多,很容易把人绕晕。本文尝试在表面梳理一下响应式编程的脉络,力求清晰,供各位想深入研究的有所参考。
要理解响应式编程的脉络,就需要将这个词拆分成两部分:响应式 和 编程。
编程
编程指的是编程范式,计算机语言发展到今天,出现了很多编程范式(详见维基百科),响应式编程是最近几年流行起来的。除了响应式编程之外,我们常用的编程范式还有命令式编程和在命令式编程基础上扩展的面向对象编程以及函数式编程。
命令式编程也称为指令式编程,可以理解为运算语句,循环语句,条件分支语句和无条件分支语句(goto语句)形式的编程。
面向对象编程在命令式编程基础上添加了对象扩展。
函数式编程最重要的基础是λ演算(lambda calculus)。相比命令式编程,其更加强调程序执行的结果而非执行的过程,倡导利用若干简单的执行单元让计算结果不断渐进,逐层推导复杂的运算,而不是设计一个复杂的执行过程,而且λ演算的函数可以接受函数当作输入(引数)和输出(传出值)。
因此,总结一下,现在流行的编程范式:命令式、面向对象、函数式和响应式。
响应式
在命令式编程中,对于语句:a:=b+c,当语句执行时,a获得了语句的执行结果,此后,参数b和c的任何改变对a没有影响。在响应式编程中,对于语句:a:=b+c,当参数b和c发生变化时,a会自动随着变化,而不必重新执行语句。
一些直观的示例可以更好的理解“响应”,如:Excel表格中,某个单元格产生变化时,其它单元格也会产生相应的变化。APP从服务器接收到某条交易记录时自动显示在UI界面上。
响应式作为一种设计思想在不同层面不同维度可以有不同的应用。应用到平常意义的数据流层面,就是Reactive Stream;如果应用到服务流层面,就是响应式微服务;用在Web设计上就有了响应式Web设计;用在架构层面就是响应式架构。
响应式编程
响应式编程是一种面向数据流和变化传播的异步编程范例,数据流可以是I/O,事件等。
通常,某种具体的编程语言都会倾向于特定的编程范式,如Fortran语言是命令式编程语言,Java在设计上更加支持面向对象编程,Haskell是函数式编程语言,而Scala则同时支持函数式和面向对象编程。响应式编程没有特定的编程语言,其实现是建立在现有编程语言基础之上的,因此就有:
命令响应式编程(imperative reactive programming)
面向对象响应式编程(object-oriented reactive programming)
函数响应式编程(functional reactive programming)
具体实现
针对响应式编程理论,当前主流实现有两类:一种是函数响应式编程FPR,一种是具有函数风格的响应式实现——响应式函数编程RFP(reactive-functional programming)。
注意,这是两种不同的实现,函数响应式编程FRP是建立在函数编程之上的响应式实现;响应式函数编程RFP是在命令式操作系统之上的一层抽象,借鉴了函数式编程风格,用于处理异步和事件驱动场景,同时可以避免像计算机需要跨线程和网络边界处理复杂的状态那样思考问题。
函数响应式编程FPR有基于Scala语言实现的Akka-Streams,响应式函数编程RFP有ReactiveX和Reactor等。
ReactiveX
ReactiveX,即Reactive Extension,响应式扩展Rx。
Eric于2007年夏天在Microsoft创建了Rx,2009年11月18日Rx.Net发布,并移植到Microsoft.Phone.Reactive for Windows Phone 7。Jafar Husain于2011年离开Microsoft加入Netflix,开始布道Rx并在Netflix的客户端UI栈完整地实现了异步流式处理。然后,他开始推动负责Netflix中间层API的Ben Christensen使用Rx。Ben于2012年开始RxJava并在2013年将代码迁移到Github。
随着Rx在业界越来越受欢迎,Eric于2012年离开Microsoft并创建了Applied Duality公司,将所有精力投入到构建标准化的跨语言,跨平台的异步实时数据流式处理API,即ReactiveX.io。
当前,Rx包括RxJava,RxJS,Rx.Net,RxScala,RxClojure,RxSwift等18种语言实现。
Reactor
Reactor项目是Spring基于Reactive Streams规范(由4个简单的Java接口:Publisher,Subscriber,Subscription 和 Processor,一个文本规范和一个TCK组成)提供的响应式实现,目的是为了让Spring生态体系能够支持业界越来越火的响应式开发。
Spring并未直接引入类似RxJava来作为其框架的一部分,而是选择另造轮子。从Spring 5开始,开发人员就可以有Spring Web Reactive和Spring Web MVC两种选择。
当前,Reactor项目包含Reactor Core,Reactor Test,Reactor Adapter,Reactor Netty,Reactor Extra,Reactor Kafka,Reactor Core .NET 和 Reactor Core JS。
Rx的特点
本节摘自《ReactiveX/RxJava文档中文版》
Rx从同步集合的Iterable/Iterator反向演化而来,是一个使用可观察数据流进行异步编程的编程接口,ReactiveX结合了观察者模式、迭代器模式和函数式编程的精华。
使用观察者模式
创建:Rx可以方便的创建事件流和数据流
组合:Rx使用查询式的操作符组合和变换数据流
监听:Rx可以订阅任何可观察的数据流并执行操作
简化代码
函数式风格:对可观察数据流使用无副作用的输入输出函数,避免了程序里错综复杂的状态
简化代码:Rx的操作符通通常可以将复杂的难题简化为很少的几行代码
异步错误处理:传统的try/catch没办法处理异步计算,Rx提供了合适的错误处理机制
轻松使用并发:Rx的Observables和Schedulers让开发者可以摆脱底层的线程同步和各种并发问题
使用Observable的优势
Rx扩展了观察者模式用于支持数据和事件序列,添加了一些操作符,它让你可以声明式的组合这些序列,而无需关注底层的实现:如线程、同步、线程安全、并发数据结构和非阻塞IO。
在Rx中,一个观察者(Observer)订阅一个可观察对象(Observable)。观察者对Observable推送的数据或数据序列作出响应。这种模式可以极大地简化并发操作,因为它创建了一个处于待命状态的观察者哨兵,在未来某个时刻响应Observable的通知,不需要阻塞等待Observable推送数据。
概念与术语
Reactive
直译为反应性的,有活性的,根据上下文一般翻译为反应式、响应式
Iterable
可迭代对象,支持以迭代器的形式遍历,许多语言中都存在这个概念
Observable
可观察对象,在Rx中定义为更强大的Iterable,在观察者模式中是被观察的对象,一旦数据产生或发生变化,会通过某种方式通知观察者或订阅者
Observer
观察者对象,监听Observable推送的数据并做出响应,Subscriber是它的一个特殊实现
Future
(摘自Scala官方文档)
所谓Future,是一种用于指代某个尚未就绪的值的对象。而这个值,往往是某个计算过程的结果:若该计算过程尚未完成,我们就说该Future未就位;若该计算过程正常结束,或中途抛出异常,我们就说该Future已就位。
Future的就位分为两种情况:当Future带着某个值就位时,我们就说该Future携带计算结果成功就位。当Future因对应计算过程抛出异常而就绪,我们就说这个Future因该异常而失败。
Future的一个重要属性在于它只能被赋值一次。一旦给定了某个值或某个异常,future对象就变成了不可变对象——无法再被改写。
Promise
(摘自Scala官方文档)
如果说futures是为了一个还没有存在的结果,而当成一种只读占位符的对象类型去创建,那么promise就被认为是一个可写的,可以实现一个future的单一赋值容器。这就是说,promise通过这种success方法可以成功去实现一个带有值的future。相反的,因为一个失败的promise通过failure方法就会实现一个带有异常的future。
Push vs Pull
当我们使用迭代遍历一个集合时,我们是从集合中拉取(Pull)数据的。当我们在集合或数据流上使用观察者模式时,数据是推送给观察者的。
Sync vs Async
在Rx中,可观察对象Observable同时支持同步和异步实现。
Lazy vs Eager
在Rx中,可观察对象Observable是有惰性的,只有被订阅时,它才推送变化。这不同于eager类型如Future。
Concurrency vs Parallel
在Rx中,一个可观察对象Observable流既不支持并发也不支持并行。不过,在一组异步的可观察对象Observable流集合可以执行并发和并行处理操作。
结论
本文粗略梳理了响应式编程的概念体系,深入研究和实践还需要沿着这条脉络进行深层次的挖掘。不当之处请回复指正。
以上是关于漫谈响应式编程的主要内容,如果未能解决你的问题,请参考以下文章