反应式编程

reactive 是一种新的编程思想, 如同名字一样, 反应式编程。而Reactor 是一个工具包,类似于 Spring一样。这点我们可以直接在Spring的官网上可以看到。本篇基于小编自己的学习进行总结。

# 一、提出问题

目前来说反应式编程在Java行业其实不是很流行, 其原因1在于传统的编程模型已经根深蒂固。虽然阻塞但是其实对于业务开发 并不是一个很大的痛点。其2新的编程思想具有学习成本,但是又不是特别的痛,所以没有引起关注。下面我们来带着问题来学习吧。

# 1.1 什么是反应式编程?

哎,可能因为都是从外国翻译过来的缘故,总喜欢翻译写高大上,且晦涩难懂的文字进行描述,搞得大多数程序猿一头雾水。但是没办法, 谁让你不主动去学习原文,而要吃一些大牛的二手翻译资料呢。所以我们就要最这些二手资料进行重读,并且深入思考,来总结出自己的理解。 小编理解,所谓反应式编程,简单来说就是基于事件编程,由事件去驱动。比如我们servlet api,传统的方式servlet 线程是阻塞线程, 如果方法没有执行完成,那么servlet线程会一直在阻塞等待。从而会导致不能接受更多的外部请求。而如果要使用反应式编程

# 1.2 反应式编程中背压指得是什么?

我也不知道为什么称背压,如果单从这个词汇来说,想死都想不通。什么鬼玩意呀。现在我们忽略这个sb的词汇。直接来说他的含义。 要想搞明白这个,先知道事件驱动是如何设计的。首先有一个事件发送者,和一个事件处理者。传统的方式是事件处理者被动的来接受 事件发送者,发起的事件,并进行处理,而在reactor中,事件的处理者不仅可以被动的接受,同时也支持主动的拉去事件。于是这种 能力被称为背压。在高大上的解释就是,这能实现组件之间的弹性。

# 1.3 反应式编程好处是什么?

我们直接看官网的说明,然后进行白话翻译。

Reactive systems better utilize modern processors. Also, the inclusion of back-pressure in reactive programming ensures better resilience between decoupled components.

直白点就是可以充分的利用其cpu多核多线程的处理能力, 另外背压的能力,使组件知道当前的负载,动态的确定自己还能接受的任务数量,称之为弹性。

# 二、Reactor 核心类

这种编程思想其实还是值得学习的,因为基于事件来驱动,确实可以充分的利用其cpu多核多线程的处理能力。充分压榨cpu的能力。 其实我们在很多地方都能看到类似的设计思想。eg: RxJava, Netty。 下面我们就学习下如何使用吧。

# 2.1 Publisher 发布者

发布者只有一个接口,提供订阅能力。

public interface Publisher<T> {// 绑定一个订阅者public void subscribe(Subscriber<? super T> s);
}
1 2 3 4

# 2.2 Subscriber 订阅者

订阅者主要处理发布者发布的信息

public interface Subscriber<T> {// 确定订阅关系public void onSubscribe(Subscription s);// 处理数据public void onNext(T t);// 错误处理public void onError(Throwable t);// 当事件处理完时触发public void onComplete();
}
1 2 3 4 5 6 7 8 9 10

# 2.3 Subscription 订阅关系

订阅关系,可以取消订阅,通知可以实现拉去能力。

public interface Subscription {// 获取指定数量的数据public void request(long n);// 取消订阅关系public void cancel();
}
1 2 3 4 5 6

# 2.4 Sink 数据池

Sink#next会将数据放入池中,由Sink缓存或直接发送给订阅者。

Mono和Flux分别提供了create和generate的方法,用来绑定事件发射器 Sink。开发者可以利用Sink来 生产事件数据,然后发送给订阅者。

# 三、事件模式

Push推模式,PUSH_PULL混合模式

enum CreateMode {PUSH_ONLY, PUSH_PULL
}
1 2 3

# 3.1 Pull 模式

generate 方法适用于拉去模式,当订阅者调用Subscription#request,则从Sink#next生产一条数据。 如下两个代码示例。

@Test@DisplayName("Flux Pull模式 Integer.MAX_VALUE")public void testFluxPull() {Flux.generate((Consumer<SynchronousSink<Integer>>) sink -> {int k = (int) (Math.random() * 10);sink.next(k);})// 默认获取 request(Integer.MAX_VALUE).subscribe(integer -> System.out.println("Pull:" + integer));}@Test@DisplayName("Flux Pull模式 request调用一次,则调用Sink生产一次")public void testFluxPullTwo() {Flux.generate((Consumer<SynchronousSink<Integer>>) sink -> {int k = (int) (Math.random() * 10);sink.next(k);}).subscribe(new Subscriber<Integer>() {Subscription subscription;private int count;@Overridepublic void onSubscribe(Subscription s) {this.subscription = s;// 订阅时候,生产1条数据this.subscription.request(1);}@Overridepublic void onNext(Integer integer) {count++;System.out.println("处理:" + integer);// 在处理1次,当第二次处理时候,就不拉数据了if (count < 2) {this.subscription.request(1);}}@Overridepublic void onError(Throwable t) {System.out.println("onError");}@Overridepublic void onComplete() {System.out.println("onComplete");}});}
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51

处理:3
处理:1
1 2

# 3.2 Push 模式

发布者主动推动数据,跟Pull的区别是。他不会随着,订阅者调用Subscription#request,而从Sink#next生产一条数据。 只有订阅时候Subscription#request,Sink只会执行一次

@Test@DisplayName("Flux Push模式")public void testFluxPush() {Flux.create((Consumer<FluxSink<Integer>>) sink -> {int k = (int) (Math.random() * 10);sink.next(k);}).subscribe(new Subscriber<Integer>() {Subscription subscription;@Overridepublic void onSubscribe(Subscription s) {this.subscription = s;this.subscription.request(1);}@SneakyThrows@Overridepublic void onNext(Integer integer) {System.out.println("处理:" + integer);}@Overridepublic void onError(Throwable t) {System.out.println("处理失败");}@Overridepublic void onComplete() {System.out.println("处理完成");}});}
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33

处理:9
1

# 四、事件驱动的好处

反应式编程的好处, 主要是编程思想的不同, 抓住关键点非阻塞+事件驱动。

StopWatch '耗时统计': running time = 2070915374 ns
---------------------------------------------
ns         %     Task name
---------------------------------------------
063036666   003%  基于事件驱动的编程思想
2007878708  097%  传统阻塞式的编程思想
1 2 3 4 5 6

如下举一个例子,假如这是Servlet API。Servlet 线程负责调用getMonoUserName()。但是其实没有执行 处理逻辑,而真正的执行逻辑交给业务线程处理。而此时Servlet线程可以释放出来,继续接受外部请求。

@Test@DisplayName("Mono 事件驱动的好处")public void testMono() {StopWatch stopWatch = new StopWatch();stopWatch.start("基于事件驱动的编程思想");Mono<String> userNameMono = getMonoUserName();stopWatch.stop();stopWatch.start("传统阻塞式的编程思想");System.out.println(getUserName());stopWatch.stop();System.out.println(userNameMono.block());System.out.println(stopWatch.prettyPrint());}@SneakyThrowspublic String getUserName() {Thread.sleep(2000L);return "JayChou";}/*** 基于事件驱动的编程思想** @return Mono<String>*/public Mono<String> getMonoUserName() {return Mono.create(monoSink -> {try {Thread.sleep(2000L);} catch (InterruptedException e) {monoSink.error(new RuntimeException(e));return;}monoSink.success("JayChou");});}
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38

# 五、总结 & 思考

传统的编程思想是: 基于数据处理来写处理逻辑,逻辑中可能直接就阻塞了。 反应式编程思想是: 我们只写数据处理逻辑,里面虽然也有阻塞,但是并不直接执行。类似线程中,Future#get

其主要的不同就是编程思想不同,非阻塞的编程思想。但是我们也发现, 这样的思想其实带来好处其实并不是很大。 我们也可以直接使用多线程来直接搞定,而不用增加学习成本来学习新的框架。

为什么反应式编程在后端开发者里面推广不起来

作为后台服务, 开发者其实对吞吐量并不是很关心,比如页面请求了后端,就算我后端服务慢,前台请求就会卡住。卡住就卡住等待呗,不管用什么框架都会卡住。(秒杀高并发服务除外,并不是所有的服务都要求高并发。特殊情况特殊处理, 异步也解决不了高并发的吞吐和rt问题)

但是如果作为安卓开发呢? 用户发起了一个请求, 请求慢就让用户主线程就卡住,手机不能滑动。这样用户体验是非常的差的。所以安卓开发会比较关注,解决方案就是纯异步,主线程只接受请求,然后任务安排给后台异步线程,这样就算请求慢,但是用户不会感觉手机是卡顿的。等到异步任务执行完,在跳转出来就行了。

所以RxJava 是鼻祖,Reactor是追随者。也是因为上面的特性,所以后台开发者没有安卓开发者感兴趣,不需要压榨机器的性能。

Reactor要想推广起来,必须要与异步Servlet或是Spring WebFlux结合(开发者无感使用),或是云原生应用彻底推广起来,强制开发者必须使用。才可能推广使用起来。 但是不管怎么样这种编程思想是可以借鉴。

Reactive 反应式编程相关推荐

  1. 玩转Spring—Spring5新特性之Reactive响应式编程实战

    1 什么是响应式编程 一句话总结:响应式编程是一种编程范式,通用和专注于数据流和变化的,并且是异步的. 维基百科原文: In computing, reactive programming is an ...

  2. Reactive 响应式编程简单使用

    Reactive Stream 模型 了解reactive stream(Flow类) 在介绍java版本的reactive stream之前,我们先回顾一下reactive stream需要做哪些事 ...

  3. Reactive(1) 从响应式编程到好莱坞

    目录 概念 面向流设计 异步化 响应式宣言 参考文档 概念 Reactive Programming(响应式编程)已经不是一个新东西了. 关于 Reactive 其实是一个泛化的概念,由于很抽象,一些 ...

  4. java9 反应编程_Java9第四篇-Reactive Stream API响应式编程

    file 我计划在后续的一段时间内,写一系列关于java 9的文章,虽然java 9 不像Java 8或者Java 11那样的核心java版本,但是还是有很多的特性值得关注.期待您能关注我,我将把ja ...

  5. 未来:spring响应式编程 Hands-On Reactive Programming in Spring 5 ,为啥需要响应式编程

    Why Reactive Spring? 为什么 使用响应式 的spring In this chapter, we are going to explain the concept of react ...

  6. 什么是反应式编程? 这里有你想要了解的反应式编程 (Reactive programming)

    理解反应式编程 你曾有过订阅报纸或者杂志的经历吗?互联网的确从传统的出版发行商那儿分得了一杯羹,但是过去订阅报纸真的是我们了解时事的最佳方式.那时,我们每天早上都会收到一份新鲜出炉的报纸,并在早饭时间 ...

  7. 什么是响应式编程(Reactive Programming)

    1.什么是响应式编程(Reactive Programming) Wikipedia上这样说: In computing, reactive programming is an asynchronou ...

  8. 未来:spring响应式编程 Hands-On Reactive Programming in Spring 5(二)------Basic Concepts

    看完这篇文章你会有很大收获! 好学近乎知,力行近乎仁,知耻而后勇. The previous chapter explained why it is important to build reacti ...

  9. 响应式编程(Reactive Programming)是什么?

    简介 在计算中,响应式编程(Reactive Programming)是一种面向数据流和变化传播的声明式编程范式. 这意味着可以在编程语言中很方便地表达静态或动态的数据流,而相关的计算模型会自动将变化 ...

最新文章

  1. android studio 加固和签名
  2. 数据港:攻破OPEX+SLA难题,实现全生命周期效能管理
  3. python 中国社区_python
  4. md5生成一个加盐程序c语言,MD5在编程中的实现 (C语言)
  5. webpack打包原理
  6. 各年龄段都是怎么提加薪的?
  7. Java关键字(三)——static
  8. Clojure 学习入门(13)- binding
  9. GridView冻结列的实现
  10. 51单片机C语言堆栈,《单片机C语言试题》(一)20101027
  11. Atitit ocr的艺术 艾提拉著 目录 1. OCR可以说是一门非常“古老”的技术,在上世纪50年代到90年代, 1 1.1. 场景文字识别技术(Scene Text Recognition,
  12. js导出excels表格.XLSX
  13. arptables实现ARP报文IPMAC绑定
  14. python中三元运算符_Python中三元表达式的几种写法介绍
  15. 使用Houdini快速将图片转换成文字模型
  16. FRED应用:激光二极管光源耦合到光纤的仿真
  17. 赔 1100 万美元!谷歌招聘年龄歧视
  18. 什么是CODECO 报文?
  19. [COGS1487]麻球繁衍(概率dp)
  20. 该如何选择手机群控系统,小白必看,防进深坑。

热门文章

  1. C++线程学习4,多线程通信和同步
  2. python实现DBSCAN聚类
  3. 小米电脑桌面没见计算机怎么办,手机屏幕太小?一分钟教会你小米手机投屏电脑方法,低调收藏!...
  4. Rosalind Java| Complementing a Strand of DNA
  5. 怎么才能写出好的代码
  6. 【PCL模块解析 05 之KDTree】01 KDTree原理及代码解析
  7. 【Zotero高效知识管理】(4)Zotero的文献管理、阅读及笔记知识管理
  8. python3.7反编译生成的.exe
  9. 【北邮国院大三上】互联网协议_Internet Protocol_PART A
  10. Linux Kernel Panic报错解决思路