您现在的位置是:亿华云 > IT科技类资讯
一文读懂响应式编程到底是什么?
亿华云2025-10-03 13:58:08【IT科技类资讯】7人已围观
简介最近几年,随着Go、Node 等新语言、新技术的出现,Java 作为服务器端开发语言老大的地位受到了不小的挑战。虽然Java 的市场地位在短时间内并不会发生改变,但Java 社区还是将挑战视为机遇,并
最近几年,文读随着Go、懂响到底Node 等新语言、应式新技术的编程出现,Java 作为服务器端开发语言老大的文读地位受到了不小的挑战。虽然Java 的懂响到底市场地位在短时间内并不会发生改变,但Java 社区还是应式将挑战视为机遇,并努力、编程不断地提高自身应对高并发服务器端开发场景的文读能力。
为了应对高并发服务器端开发场景,懂响到底在2009 年,应式微软提出了一个更优雅地实现异步编程的编程方式—— Reactive Programming ,我们称之为响应式编程。文读
随后,懂响到底各语言很快跟进,应式都拥有了属于自己的响应式编程实现。比如,JavaScript 语言就在ES6 中通过Promise 机制引入了类似的异步编程方式。同时,Java 社区也在快速发展,Netflix 和LightBend 公司提供了RxJava 和Akka Stream 等技术,使得Java 平台也有了能够实现响应式编程的框架。
当下,我们通过Mina 和Netty 这样的云南idc服务商NIO 框架其实就能完成高并发下的服务器端开发任务,但这样的技术只掌握在少数高级开发人员手中,因为它们难度较大,并不适合大部分普通开发者。
虽然目前已经有不少公司在实践响应式编程,但整体来说,其应用范围依旧不大。出现这种情况的原因在于当下缺少简单、易用的技术,这些技术需要能使响应式编程更加普及,并做到如同Spring MVC 一样结合Spring 提供的服务对各种技术进行整合。
在2017 年9 月28 日,Spring 5 正式发布。Spring 5 发布最大的意义在于,它将响应式编程技术的普及向前推进了一大步。而同时,作为在背后支持Spring 5 响应式编程的框架Spring Reactor,也进入了里程碑式的3.1.0 版本。
响应式编程到底是什么?
在现实生活中,当我们听到有人喊我们名字的时候,会对其进行响应,也就是亿华云说,我们是基于事件驱动模式来进行编程的。所以这个过程其实就是下发产生的事件,然后我们作为消费者对下发事件进行一系列的消费。
从这个角度来说,对整个代码的设计应该是针对消费者来进行的。比如,看电影,有些画面我们不想看,那就闭上眼睛;有些声音不想听,那就捂上耳朵。其实这就是对消费者的增强包装,我们把复杂的逻辑拆分开,然后将其分割成一个个小任务进行封装,于是就有了诸如filter、map、skip、limit 等操作。
01
并发与并行的关系
可以说,并发很好地利用了CPU 时间片的源码库特性,也就是操作系统选择并运行一个任务,接着在下一个时间片内运行另一个任务,并把前一个任务设置成等待状态。其实并发并不意味着并行。
具体列举下面几种情况。
① 有时候,多线程执行会提高应用程序的性能,而有时候反而会降低应用程序的性能。这在 JDK 中Stream API 的使用上体现得很明显,如果任务量很小,而我们又使用了并行流,反而降低了应用程序的性能。
② 在多线程编程中,可能会同时开启或者关闭多个线程,这样会产生很大的性能开销, 也降低了应用程序的性能。
③ 当线程同时处于等待I/O 的过程中时,并发可能会阻塞CPU 资源,其后果不仅是用户长时间等待,而且会浪费CPU 的计算资源。
④ 如果几个线程共享了一个数据,情况就会变得有些复杂。我们需要考虑数据在各个线程中的状态是否一致。为了达到数据一致的目的,很可能会使用synchronized 或者lock 相关操作。
现在,你对并发有一定的了解了吧。并发很好,但并不一定会实现并行。并行是在多核CPU 上同一时间运行多个任务或者一个任务分为多块同时执行(如ForkJoin)。单核CPU 的话,就不要考虑并行了。
补充一点,实际上多线程就意味着并发,但是并行只发生在这些线程在同一时间调度、分配到不同CPU 上执行的情况下。也就是说,并行是并发的一种特定形式。一个任务里往往会产生很多元素,这些元素在不参与操作的情况下大都只能处于当前线程中,这时我们可以对其进行ForkJoin,但这对很多程序员来讲有时候很不好操作、控制,上手难度有些大。这时如果用响应式编程,就可以简单地通过所提供的调度API 轻松做到事件元素的下发、分配,其内部会将每个元素包装成一个任务并提交到线程池中,我们可以根据任务是计算型的还是I/O 型的来选择相应的线程池。
在这里,需要强调一下,线程只是一个对象,不要把它想象成CPU 中的某一个执行核心,这是很多人都在犯的错,CPU 时间片会切换执行这些线程。
02
如何理解响应式编程中的背压
背压,由Back Pressure 翻译得到,从英文字面意思讲,称之为回压可能更合适。首先解释一下回压,它就好比用吸管喝饮料,将吸管内的气体吸掉,吸管内形成低压,进而形成饮料至吸管方向的吸力,此吸力将饮料吸进人嘴里。我们常说人往高处走,水往低处流,水之所以会出现这种现象,其实是重力所致。而现在吸管下方的水上升进入人的口中,说明出现了下游指向上游的逆向压力,而且这个逆向压力大于重力,可以称这种情况为背压。这是一个很直观的词,向后的、往回的压力——Back Pressure。
放在程序中,也就是在数据流从上游源生产者向下游消费者传输的过程中,若上游源生产速度大于下游消费者消费速度,那么可以将下游想象成一个容器,它处理不了这些数据,然后数据就会从容器中溢出,也就出现了类似于吸管例子中的情况。现在,我们要做的事情就是为这个场景提供解决方案,该解决方案被称为背压机制。
为了更好地解决背压带来的问题,我们回到现实中看一个事物——大坝。在发洪水期间,下游没办法一下子消耗那么多水,大坝此时的作用就是拦截洪水,并根据下游的消耗情况酌情排放,也就是说,背压机制应该放在连接元素生产者和消费者的地方,即它是生产者和消费者的衔接者。然后,根据上面对大坝的描述,背压机制应该具有承载元素的能力,也就是它必须是一个容器,而且其存储与下发的元素应该有先后顺序,那么这里使用队列是最适合的了。背压机制仅起承载作用是不够的,正因为上游进行了承压,所以下游可以按需请求元素,也可以在中间根据实际情况进行限流,以此上下游共同实现了背压机制。在本书后续内容及相关的配套视频中会介绍背压的相关API。
03
Reactor 与RxJava 的对比
关于响应式编程,我写的《Java 编程方法论:响应式RxJava 与代码设计实战》一书已经出版,那么Reactor 与RxJava 又有什么区别呢?首先我要明确地告诉你,如果你使用的是Java 8+,那么推荐使用Reactor 3,而如果你使用的还是Java 6+或函数需要做异常检查,那么推荐使用RxJava 2。
从上图可以看到,RxJava 2 和Reactor 共用了一套接口API 标准Reactive Streams Commons,这也说明它们的最终目的是一致的,而且API 具有通用性,这样也降低了学习成本。
下面再来回顾一下RxJava。
迄今为止,RxJava 发行版主要分三大版本RxJava 3、RxJava 2 和RxJava 1。与RxJava 1 不同,RxJava 3、RxJava 2 直接通过新添加的Flowable 类型来实现Publisher 的接口定义(RxJava 3 与RxJava 2 并没有太多区别,故这里只介绍RxJava 2)。同时,RxJava 2 依然保留了RxJava 1 中的Observable、Completable 和Single,并引入了支持Optional 的Single 升级版——Maybe 类型。RxJava 1 中的Observable 不支持RxJava 2 中的背压机制,背压机制是Flowable 的专有功能,不过Observable 内部提供了可转换API。需要注意的是,Observable 实现的是RxJava 2 中自定义的ObservableSource 接口。
在Reactor 中,可以发现Mono 和Flux 两种类型都实现了Publisher 接口,同时两者皆实现了背压机制。Flux 可以对标RxJava 2 中的Flowable 类型,而Mono 可以被理解为RxJava 2 中对Single 的背压加强版。后续,我们会进行更深入的讲解。
同样,下面再来了解一下Reactor 与RxJava 的不同之处。
为了兼容 Java 1.6+ ,RxJava 不得不自行定义了一些函数式接口,可以参考io.reactivex.functions 下的接口定义。而Reactor 3 则是基于JDK 中提供的java.util.function 来设计实现的。 可以很轻松地从java.util.stream.Stream 转换为Flux,也可以很轻松地由后者转换为前者。 同样,可以很轻松地实现CompletableFuture 与Mono 之间的互相转换,也可以轻松而安全地基于Optional 类型的元素创建Mono。 Reactor 3 可以更好地服务于Spring Framework 5,也更适应最新版本的JDK。最后,我们再简单介绍一下上图中的几个部分。
Core 是我们主要研究的库,是Reactor 的核心实现库。其作用与RxJava 2 的核心实现的作用是一样的,本书主要介绍reactor-core 模块。
IPC 可以认为它是针对encode、decode、send(unicast、multicast 或request/response )及服务连接而设计的支持背压的组件。IPC 支持Kafka、Netty 及Aeron。
Addons 其中包括reactor-adapter、reactor-logback 和reactor-extra。reactor-adapter 可以说是连接RxJava 1/2 中Observable、Completable、Flowable、Single、Maybe、Scheduler 的桥梁,可以方便地与Reactor 3 进行转换操作。同样,这个库对于Swing/SWT Scheduler、Akka Scheduler 也做了针对性适配。reactor-logback 用于支持Reactor Core 异步处理Logback 方面的功能。reactor-extra 为数字类型的Flux 源提供了很多数学运算的操作。
Reactive Streams Commons 是RxJava 2 和Reactor 共用的一套接口API 标准。
很赞哦!(7626)