Reactive Programming
Reactive的表现
Reactive 规范是 JVM Reactive 扩展规范 Reactive Streams JVM,而 Reactive 实现框架则是最典型的实现:
Reactive Streams /Java 9
一个非常底层的约定,提供了Publisher和Subscriber接口。 Java 9 提供了Flow API 的支持
Spring Framework 5.0 / Reactor
Spring 5,以 Reactive 为基础的Reactor框架 ,逐步构建一套完整的 Reactive 技术栈,例如 WebFlux,类似于Spring MVC的功能
RxJava
Netflix开源的技术
为什么会出现
这些实现都是怎么说的
reactor
http://projectreactor.io/docs/core/release/reference/#_blocking_can_be_wasteful
3.1. Blocking Can Be Wasteful
阻塞导致性能瓶颈和浪费资源
增加线程可能会引起资源竞争和并发问题
并行的方式不是银弹(不能解决所有问题)
理解阻塞的弊端
理解并行的复杂
异步
3.2. Asynchronicity to the Rescue?
Callbacks 是解决非阻塞的方案,然而他们之间很难组合,并且快速地将代码引导至 "Callback Hell" 的不归路
Futures 相对于 Callbacks 好一点,不过还是无法组合,不过 CompletableFuture 能够提升这方面的不足
理解 "Callback Hell"
Future 的限制
阻塞 链式
CompletableFuture 不仅可以支持 Future 链式操作,而且提供三种生命周期回调,即执行回调(Action)、完成时回调(Complete)、和异常回调(Exception),类似于 Spring 4 ListenableFuture 以及 Guava ListenableFuture。
Reactive Streams JVM . http://www.reactive-streams.org/
认为异步系统和资源消费需要特殊处理
流式数据容量难以预判
异步编程复杂
数据源和消费端之间资源消费难以平衡
什么是 Reactive Programming
关于什么是 Reactive Programming,下面给出六种渠道的定义,尝试从不同的角度,了解 Reactive Programming 的意涵。首先了解的是“The Reactive Manifesto” 中的定义
The Reactive Manifesto 中的定义
Reactive Systems are: Responsive, Resilient, Elastic and Message Driven.
https://www.reactivemanifesto.org/
该组织对 Reactive 的定义非常简单,其特点体现在以下关键字:
响应的(Responsive)
适应性强的(Resilient)
弹性的(Elastic)
消息驱动的(Message Driven)
不过这样的定义侧重于 Reactive 系统,或者说是设计 Reactive 系统的原则。
维基百科中的定义
维基百科作为全世界的权威知识库,其定义的公允性能够得到保证:
Reactive programming is a declarative programming paradigm concerned with data streams and the propagation of change. With this paradigm it is possible to express static (e.g. arrays) or dynamic (e.g. event emitters) data streams with ease, and also communicate that an inferred dependency within the associated execution model exists, which facilitates the automatic propagation of the changed data flow.
参考地址:https://en.wikipedia.org/wiki/Reactive_programming
维基百科认为 Reactive programming 是一种声明式的编程范式,其核心要素是数据流(data streams )与其传播变化( propagation of change),前者是关于数据结构的描述,包括静态的数组(arrays)和动态的事件发射器(event emitters)。由此描述,在小马哥脑海中浮现出以下技术视图:
数据流:Java 8 Stream
传播变化:Java Observable/Observer
事件/监听:Java EventObject/EventListener
这些技术能够很好地满足维基百科对于 Reactive 的定义,那么, Reactive 框架和规范的存在意义又在何方?或许以上定义过于抽象,还无法诠释 Reactive 的全貌。于是乎,小马哥想到了去 Spring 官方找寻答案,正如所愿,在 Spring Framework 5 官方参考文档中找到其中定义。
Spring 5 中的定义
The term "reactive" refers to programming models that are built around reacting to change — network component reacting to I/O events, UI controller reacting to mouse events, etc. In that sense non-blocking is reactive because instead of being blocked we are now in the mode of reacting to notifications as operations complete or data becomes available.
参考地址:https://docs.spring.io/spring/docs/current/spring-framework-reference/web-reactive.html#webflux-why-reactive
相对于维基百科的定义,Spring 5 WebFlux 章节同样也提到了变化响应(reacting to change ) ,并且还说明非阻塞(non-blocking)就是 Reactive。同时,其定义的侧重点在响应通知方面,包括操作完成(operations complete)和数据可用(data becomes available)。Spring WebFlux 作为 Reactive Web 框架,天然支持非阻塞,不过早在 Servlet 3.1 规范时代皆以实现以上需求,其中包括 Servlet 3.1 非阻塞 API ReadListener 和WriteListener,以及 Servlet 3.0 所提供的异步上下文 AsyncContext 和事件监听 AsyncListener。这些 Servlet 特性正是为 Spring WebFlux 提供适配的以及,所以 Spring WebFlux 能完全兼容 Servlet 3.1 容器。小马哥不禁要怀疑,难道 Reactive 仅是新包装的概念吗?或许就此下结论还为时尚早,不妨在了解一下 ReactiveX 的定义。
ReactiveX 中的定义
广泛使用的 RxJava 作为 ReactiveX 的 Java 实现,对于 Reactive 的定义,ReactiveX 具备相当的权威性:
ReactiveX extends the observer pattern to support sequences of data and/or events and adds operators that allow you to compose sequences together declaratively while abstracting away concerns about things like low-level threading, synchronization, thread-safety, concurrent data structures, and non-blocking I/O.
参考地址:http://reactivex.io/intro.html
不过,ReactiveX 并没有直接给 Reactive 下定义,而是通过技术实现手段说明如何实现 Reactive。ReactiveX 作为观察者模式的扩展,通过操作符(Opeators)对数据/事件序列(Sequences of data and/or events )进行操作,并且屏蔽并发细节(abstracting away…),如线程 API(Exectuor 、Future、Runnable)、同步、线程安全、并发数据结构以及非阻塞 I/O。该定义的侧重点主要关注于实现,包括设计模式、数据结构、数据操作以及并发模型。除设计模式之外,Java 8 Stream API 具备不少的操作符,包括迭代操作 for-each、map/reduce 以及集合操作 Collector等,同时,通过 parallel() 和 sequential() 方法实现并行和串行操作间的切换,同样屏蔽并发的细节。至于数据结构,Stream 和数据流或集合序列可以画上等号。唯独在设计模式上,Stream 是迭代器(Iterator)模式实现,而 ReactiveX 则属于观察者(Observer)模式的实现。 对此,Reactor 做了进一步地解释。
Reactor 中的定义
The reactive programming paradigm is often presented in object-oriented languages as an extension of the Observer design pattern. One can also compare the main reactive streams pattern with the familiar Iterator design pattern, as there is a duality to the Iterable-Iterator pair in all of these libraries. One major difference is that, while an Iterator is pull-based, reactive streams are push-based.
http://projectreactor.io/docs/core/release/reference/#intro-reactive
同样地,Reactor 也提到了观察者模式(Observer pattern )和迭代器模式(Iterator pattern)。不过它将 Reactive 定义为响应流模式(Reactive streams pattern ),并解释了该模式和迭代器模式在数据读取上的差异,即前者属于推模式(push-based),后者属于拉模式(pull-based)。难道就因为这因素,就要使用 Reactive 吗?这或许有些牵强。个人认为,以上组织均没有坦诚或者简单地向用户表达,都采用一种模糊的描述,多少难免让人觉得故弄玄虚。幸运地是,我从 ReactiveX 官方找到一位前端牛人 André Staltz,他在学习 Reactive 过程中与小马哥一样,吃了不少的苦头,在他博文《The introduction to Reactive Programming you've been missing》中,他给出了中肯的解释。
André Staltz 给出的定义
Reactive programming is programming with asynchronous data streams.
In a way, this isn't anything new. Event buses or your typical click events are really an asynchronous event stream, on which you can observe and do some side effects. Reactive is that idea on steroids. You are able to create data streams of anything, not just from click and hover events. Streams are cheap and ubiquitous, anything can be a stream: variables, user inputs, properties, caches, data structures, etc.
"What is Reactive Programming?"
他在文章指出,Reactive Programming 并不是新东西,而是司空见惯的混合物,比如事件总监、鼠标点击事件等。同时,文中也提到异步(asynchronous )以及数据流(data streams)等关键字。如果说因为 Java 8 Stream 是迭代器模式的缘故,它不属于Reactive Programming 范式的话,那么,Java GUI 事件/监听则就是 Reactive。
那么,Java 开发人员学习 RxJava、Reactor、或者 Java 9 Flow API 的必要性又在哪里呢?因此,非常有必要深入探讨 Reactive Programming 的使用场景。
性能如何/使用场景
Reactive Programming 使用场景
正如同 Reactive Programming 的定义那样,各个组织各执一词,下面仍采用多方引证的方式,寻求 Reactive Programming 使用场景的“最大公约数”。
Reactive Streams JVM 认为的使用场景
The main goal of Reactive Streams is to govern the exchange of stream data across an asynchronous boundary.
https://github.com/reactive-streams/reactive-streams-jvm
Reactive Streams JVM 认为 Reactive Streams 用于在异步边界(asynchronous boundary)管理流式数据交换( govern the exchange of stream data)。异步说明其并发模型,流式数据则体现数据结构,管理则强调它们的它们之间的协调。
Spring 5 认为的使用场景
Reactive and non-blocking generally do not make applications run faster. They can, in some cases, for example if using the WebClient to execute remote calls in parallel. On the whole it requires more work to do things the non-blocking way and that can increase slightly the required processing time.
The key expected benefit of reactive and non-blocking is the ability to scale with a small, fixed number of threads and less memory. That makes applications more resilient under load because they scale in a more predictable way.
Spring 认为 Reactive 和非阻塞通常并非让应用运行更快速(generally do not make applications run faster),甚至会增加少量的处理时间,因此,它的使用场景则利用较少的资源,提升应用的伸缩性(scale with a small, fixed number of threads and less memory)。
ReactiveX 认为的使用场景
The ReactiveX Observable model allows you to treat streams of asynchronous events with the same sort of simple, composable operations that you use for collections of data items like arrays. It frees you from tangled webs of callbacks, and thereby makes your code more readable and less prone to bugs.
ReactiveX 所描述的使用场景与 Spring 的不同,它没有从性能入手,而是代码可读性和减少 Bugs 的角度出发,解释了 Reactive Programming 的价值。同时,强调其框架的核心特性:异步(asynchronous)、同顺序(same sort)和组合操作(composable operations)。它也间接地说明了,Java 8 Stream 在组合操作的限制,以及操作符的不足。
Reactor 认为的使用场景
Composability and readability
Data as a flow manipulated with a rich vocabulary of operators
Nothing happens until you subscribe
Backpressure or the ability for the consumer to signal the producer that the rate of emission is too high
High level but high value abstraction that is concurrency-agnostic
Reactor 同样强调结构性和可读性(Composability and readability)和高层次并发抽象(High level abstraction),并明确地表示它提供丰富的数据操作符( rich vocabulary of operators)弥补 Stream API 的短板,还支持背压(Backpressure)操作,提供数据生产者和消费者的消息机制,协调它们之间的产销失衡的情况。同时,Reactor 采用订阅式数据消费(Nothing happens until you subscribe)的机制,实现 Stream 所不具备的数据推送机制。
WebFlux 使用场景
长期异步执行,一旦提交,慢慢操作。是否适合 RPC 操作?
任务型的,少量线程,多个任务长时间运作,达到伸缩性。
Mono:单数据 Optional 0:1, RxJava : Single
Flux : 多数据集合,Collection 0:N , RxJava : Observable
函数式编程
非阻塞(同步/异步)
远离 Servlet API
API
Servlet
HttpServletRequest
不再强烈依赖 Servlet 容器(兼容)
容器
Tomcat
Jetty
Spring Cloud Gateway -> Reactor
Spring WebFlux -> Reactor
Zuul2 -> Netty Reactive
Reactive Programming 作为观察者模式(Observer) 的延伸,不同于传统的命令编程方式( Imperative programming)同步拉取数据的方式,如迭代器模式(Iterator) 。
而是采用数据发布者同步或异步地推送到数据流(Data Streams)的方案。当该数据流(Data Steams)订阅者监听到传播变化时,立即作出响应动作。
在实现层面上,Reactive Programming 可结合函数式编程简化面向对象语言语法的臃肿性,屏蔽并发实现的复杂细节,提供数据流的有序操作,从而达到提升代码的可读性,以及减少 Bugs 出现的目的。
同时,Reactive Programming 结合背压(Backpressure)的技术解决发布端生成数据的速率高于订阅端消费的问题。
Reactive Programming的更多相关文章
- .Net中的反应式编程(Reactive Programming)
系列主题:基于消息的软件架构模型演变 一.反应式编程(Reactive Programming) 1.什么是反应式编程:反应式编程(Reactive programming)简称Rx,他是一个使用LI ...
- Unity基于响应式编程(Reactive programming)入门
系列目录 [Unity3D基础]让物体动起来①--基于UGUI的鼠标点击移动 [Unity3D基础]让物体动起来②--UGUI鼠标点击逐帧移动 时光煮雨 Unity3D让物体动起来③—UGUI DoT ...
- ReactiveCocoa与Functional Reactive Programming
转自 http://blog.leezhong.com/ios/2013/06/19/frp-reactivecocoa.html Functional Reactive Programming(以下 ...
- "Principles of Reactive Programming" 之<Actors are Distributed> (1)
week7中的前两节课的标题是”Actors are Distributed",讲了很多Akka Cluster的内容,同时也很难理解. Roland Kuhn并没有讲太多Akka Clus ...
- "reactive programming"的概念
下面的内容大多是翻译来的. Reactive Programming? What is Reactive Programming? 为了了解Reactive——从编程范式至其背后的动机,有必要了解现在 ...
- "Principles of Reactive Programming" 之 <Persistent Actor State>学习笔记
这是<Pinciples of Reactive Programming>week6的最后一课. 为什么需要把actor的状态持久化? 如果actor没有状态,那么在任何实时,这个acto ...
- [Reactive Programming] RxJS dynamic behavior
This lesson helps you think in Reactive programming by explaining why it is a beneficial paradigm fo ...
- [Reactive Programming] Using an event stream of double clicks -- buffer()
See a practical example of reactive programming in JavaScript and the DOM. Learn how to detect doubl ...
- [RxJS] Reactive Programming - What is RxJS?
First thing need to understand is, Reactive programming is dealing with the event stream. Event stre ...
- 指路Reactive Programming
指路Reactive Programming Mar 02, 2016 in Engineering 我在工作中采用Reactive Programming(RP)已经有一年了,对于这个“新鲜”的辞藻 ...
随机推荐
- 【DevExpress】邮箱制作小结
利用DevExpress的RichEditControl控件可以发送包含图片的邮件.但存在一个问题.RichEdit直接将图片解析成base64码包含在RichEdit的HtmlText中,这导致客户 ...
- Hibernate运行原生sql并将查询的结果转化为对象
原生SQL查询执行的控制是通过SQLQuery接口进行的,通过执行Session.createSQLQuery()获取这个接口.下面来描述如何使用这个API进行查询.标量查询(Scalar queri ...
- Element UI toggleRowExpansion用法
背景: 官方说明文档没有具体代码示例 一.官方文档 方法名: toggleRowExpansion 说明: 用于可展开表格,切换某一行的展开状态,如果使用了第二个参数,则是设置这一行展开与否(expa ...
- 小程序 iphone X 吸底按钮适配
问题图: 解决方法: // app.js App({ isIphoneX() { let isIphoneX = false wx.getSystemInfo({ su ...
- cmd常用命令总结
1.cmd不同盘符之间切换 方法(1): cd /d 路径如:cd /d c:/windows 方法(2): d:2.cls 清空cmd窗口dir 查看文件夹下的目录md 创建文件夹rd 删除文件夹c ...
- go语言学习--内核态和用户态(协程)
go中的一个特点就是引入了相比于线程更加轻量级的协程(用户态的线程),那么什么是用户态和内核态呢? 一.什么是用户态和内核态 当一个任务(进程)执行系统调用而陷入内核代码中执行时,我们就称进程处于内核 ...
- Java程序国际化学习代码一
Java程序国际化初识 1.基本思路 Java程序的国际化的思路是将程序中的标签.提示等信息放在资源文件中,程序需要支持哪些国家.语言环境,就对应提供相应的资源文件.资源文件是key-value对,每 ...
- UIView和CALayer区别
(1)首先UIView可以响应用户的触摸事件,Layer不可以. (2)View中frame getter方法,bounds和center,UIView并没有做什么工作:它只是简单的各自调用它底层的C ...
- springmvc功能以及源码实现分析
每当我学习一个新技术时,我总是会问自己这个技术有哪些功能,能帮我解决哪些问题. 但是当我在网上进行搜索时,答案并不让我满意. 在使用springmvc很久以后,我将在这篇文章里对springmvc功能 ...
- Google瓦片地图URL
http://mt2.google.cn/vt/lyrs=y&scale=2&hl=zh-CN&gl=cn&x=6891&y=3040&z=13 //含 ...