响应式编程-基本介绍

news2024/11/16 12:33:03

响应式编程-基本介绍

什么是响应式编程

响应式宣言(The Reactive Manifesto) 对响应式系统进行了定义:响应式系统是具备以下特质即时响应性(Responsive)、回弹性(Resilient)、弹性(Elastic)以及消息驱动(Message Driven)的系统。

响应式是一种思维模式,核心在于异步和非阻塞。最初起源于IO模型的Reactor模型,并形成理念产生了各类响应式框架,贯穿整个系统使用的编程模式,从系统接受输入开始到完成完整的系统功能输出结果的完整过程中都是响应式的。

https://img-blog.csdnimg.cn/img_convert/db39eeaa35fc389a72b2ba7653cc49ea.png

1 主从多线程模型的Reactor线程模型

响应式的底层逻辑如下:阻塞是非常浪费和影响性能的,要构建一个无阻塞的系统。响应式编程有三个最重要的特点:1. 事件驱动的处理模式。 2. 只有事件/消息真正被订阅时才会执行,在此之前都是对事件/消息处理流的一种编排。3. 事件/消息处理流可以对背压进行管理。

理解响应式编程:

  1. 以监听者模式来说,当需要发布一个事件时,通常会调用所欲listener事件处理接口

        for(Listener listener :  listeners) {

            listener.onEvent(event);

        }

  1. 以上例子中如果某个listener功能发生阻塞,将造成发布者线程阻塞。为改善阻塞,引入多线程/异步的方式:

ExecutorService executor = Executors.newCachedThreadPool();

        for(Listener listener :  listeners) {

            executor.execute(()->{

                listener.onEvent(event);

            });

    }

  1. 在上面使用线程池的情况下, 线程数量受服务器限制,当事件大量增多是,可能会发生线程池处理队列满而发生阻塞的情况,如网关中涌入大量请求时的场景,因此即使每一个连接或每一个请求都做异步处理,调度线程总会在某时刻无法获取空闲线程而阻塞事件分发线程。
  2. Listener处理事件如果是响应式编程, listener将对事件的处理编排成一个执行流并返回,但不会执行他,只有当执行流被订阅时才真正执行。

比如 onEvent将返回一个MonoFlux对象。

Mono<String> result = Mono.fromSupplier(this::test);

  1. 响应式和多线程、异步的差别在哪:
    1. 响应式是惰性的,也就是在被订阅之前不会执行任何操作。而Feature或线程池总是会执行某些操作,比如放入任务队列, 申请线程等。
    2. 当收到响应式的发布者对象时,由调用者可以将其封装在响应式链条中,从而构建一个完整的响应链。
    3. 当需要订阅时(真正执行时),可以方便的使用Scheduler进行异步订阅处理。

背压是指来自后端的压力,当消息消费者的消费能力无法跟上消息发送者的能力,造成消息的积压,甚至可能由于持续的压力造成消息消费者的崩溃。类似于DDOS拒绝服务攻击的概念。异步消息驱动的系统需要能够进行背压管理,如引入消息中间件,消息将安全存储在消息中间件中,直到被可靠消费。而在响应式编程中也需要提供背压的处理机制避免消息积压和系统阻塞。

响应式编程的使用场景

响应式编程并不会提高程序的运行速度,由于存在一定的学习门和思维模式转变的原因,在业务系统的开发中并没有显示器重要性而得到应用。但在IO密集型的适用场景应用中得到了广泛的应用,如网关应用:zuul2 spring cloud gateway等。

Java 响应式流规范

       Reactive-Streams(https://www.reactive-streams.org/) 是Java语言的响应式流编程模型,并已被JDK9采用,以java.util.concurrent.Flow API提供。

      

Reactive-Stream中核心编程模型抽象:

图2 Reactor-Steam消息处理流程

消息的处理流程如下:

  1. 当对publisher进行订阅时,publisher将Subscription对象发送到消费者,消费者适用Subscription控制消息的推送。
  2. 消费者调用Subscription.request(n)方法表示,可以消费n条消息, 消息发送者消息推送至消费者直至消息数量达到n(调用消费者的onXXX方法)。
  3. 消费者持续调用Subscription.request(n)方法像消息生产者反馈自身消费能力,使得消息推送在背压得到管理的情况下持续进行。

下面是React-Stream规范定义的核心接口:

       Publisher接口:一个发送无限序列的发布者。

public interface Publisher<T> {

    void subscribe(Subscriber<? super T> var1);

}

       Subscriber接口: 定义特定事件触发的处理方法。包括onSubscribe:Publisher进行订阅时;onNext:消费消息;onError:处理异常信号;onComplete:处理结束信号。

public static interface Subscriber<T> {

    public void onSubscribe(Subscription subscription);

    public void onNext(T item);

    public void onError(Throwable throwable);

    public void onComplete();

}

       Subscription接口:Subscriber对Publisher的消息消费请求, 只有调用SubScription接口方法,消息才从Publisher传递至Subscriber,并调用Subscriber相应接口方法。

public interface Subscription {

    void request(long var1);

    void cancel();

}

       Subscription的request接口提供了从订阅者到发起者的反馈,表示可以消费n个消息,在进行request之前,发送者并不会推送消息至消费者,从而实现了背压的管理。

Reactor

Reactor

Reactor是一个Reactor-Stream规范的实现者,已被使用在了从多的框架项目中,如Spring MVC, Spring webFlux,Spring cloud gateway等。

官方文档地址如下Reactor 3 Reference Guide。

下面简单介绍一下Flux,Mono和Scheduler的概念, 其他特性详见官方文档。

Flux和Mono

Flux和Mono是Reactor Stream publisher的标准实现。都表示一个异步的消息序列,Flux表示一个产生0或无限个消息的序列(持续产生消息直至产生一个Complete消息),而Mono表示一个0-1个消息的序列。

图3 Flux会持续推送消息直至发送完成信号

图4 Mono只会产生0-1个消息

Scheduler

Reactor, 和 RxJava一样,也可以被认为是 并发无关(concurrency agnostic) 的。指的是它并不强制要求使用并发模式,将选择权交给开发者。

Reactor可以方便的再publishOn()或SubscribeOn()方法中使用Scheduler对象来是的线程的发布或订阅在

PublishOn方法将其后面的转换操作和消息消费操作在Scheduler的线程中异步执行,而SubscribeOn()则将整个执行链条都在Scheduler线程中异步执行。

基本示例

Flux<Integer> ints = Flux.range(1, 4)

      .map(i -> {

        if (i <= 3) return i;

        throw new RuntimeException("Got to 4");

      });

ints.subscribe(i -> System.out.println(i),

      error -> System.err.println("Error: " + error));

  1. Flux.rang(1,4)表示生成一个1,2,3,4的整数序列
  2. .map操作表示Flux序列将经过一个转换
  3. Ints.subscribe之前不会执行任何操作,subscribe将处罚消息流的执行,onNext()方法是打印消息元素,error方法是打印“Error:”+error

下面是Reactor-Netty-http模块中一个Http请求的Reactor使用示例:

public Mono<Void> send() {

        if (this.markSentHeaderAndBody()) {

            HttpMessage request = this.newFullEmptyBodyMessage();

            return FutureMono.deferFuture(() -> {

                return this.channel().writeAndFlush(request);

            });

        } else {

            return Mono.empty();

        }

    }

调用该Send方法会构建一个Mono<Void>对象,当对该对象进行订阅时,将实际执行一个异步操作:调用this.channel().writeAndFlsh(request)发送http请求。

总结

本文简单的介绍了响应式编程的概念及其适应场景,及Java响应式编程规范Reactor-Streaming,及其实现者Reactor进行了接收, 后续将从Spring Web,Spring Flux,Spring Cloud Gateway等主流框架中对Reactor的使用来挖掘响应式编程的魅力。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1181334.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

Freeswitch API调用方式

1.API调用方式 可以复制下面内容成.bat文件直接在windows下运行&#xff0c;修改成对应的ip加端口。 echo off SETLOCAL :_starting cls set inputecho echo 1 add agent 21009 11 uuid_check 21009 21 list users 31 check modules …

JAVA中类和对象的认识

1、面向对象的初步认知 1.1 什么是面向对象 Java是一门纯面向对象的语言(Object Oriented Program&#xff0c;简称OOP)&#xff0c;在面向对象的世界里&#xff0c;一切皆为对象。面 向对象是解决问题的一种思想&#xff0c;主要依靠对象之间的交互完成一件事情。用面向对象的…

LabVIEW示波器连续触发编程

LabVIEW示波器连续触发编程 niScopeEX Fetch Forever范例利用了如何设置硬件和驱动的优点来进行连续采集。 当NI-SCOPE设备被设置为采集预触发扫描&#xff0c;设备上的板载内存被用作一个环形缓冲。这样&#xff0c;无论触发何时到来&#xff0c;设备都可以追踪和检索所有要求…

Ubuntu开机无法进入系统,文件根系统目录空间不足导致?

前言&#xff1a; 自己电脑上装的是Win11和Ubuntu20双系统&#xff0c;平时就是切换着用。 偶然有次&#xff0c;Ubuntu提示文件根系统目录空间不足&#xff0c;自己没在意。 结果下次开机进入Ubuntu时候&#xff0c;芭比Q了。。进不了系统 这样的事情发生很多次了&#xff0c;…

密度聚类与层次聚类

大家好&#xff0c;我是带我去滑雪&#xff01; 密度聚类&#xff08;Density-based Clustering&#xff09;和层次聚类&#xff08;Hierarchical Clustering&#xff09;是两种不同的聚类方法&#xff0c;用于将数据集中的数据点分组成簇。 目录 一、密度聚类 &#xff08;…

高频时序数据仓库-在线课堂二

详细了解天软高频时序数据仓库的构架及性能后&#xff0c;本周天软在线课堂将带来高频时序数据仓库的应用展示。扫描图片二维码可报名参会。

MATLAB|热力日历图

目录 日历图介绍&#xff1a; 热力日历图的特点&#xff1a; 应用场景&#xff1a; 绘图工具箱 属性 (Properties) 构造函数 (Constructor) 公共方法 (Methods) 私有方法 (Private Methods) 使用方法 日历图介绍&#xff1a; 热力日历图是一种数据可视化形式&#xf…

Pioneer电源维修PM36218B-10P-1-8PH-J

开关电源出现不启振的时候&#xff0c;我们通常需要查看开关频率是否正确、保护电路是否断路、电压反馈电路、电流反馈电路又没问题&#xff0c;开关管是否击穿等。 pioneer电源维修时&#xff0c;PWM模块为UC3843&#xff0c;检测未发现其他异常&#xff0c;在R(220K)上并接一…

美妆行业如何通过自媒体提升品牌曝光

自媒体的出现使美妆行业的推广方式产生了变化&#xff0c;自媒体平台的用户年轻化、用户基数大、消费力较强&#xff0c;能够接受新鲜事物&#xff0c;为美妆品牌带来广阔的市场和消费人群。 因此自媒体平台的内容运营十分重要&#xff0c;今天媒介盒子就来和大家聊聊&#xf…

VBA技术资料MF80:选择文件及文件夹

我给VBA的定义&#xff1a;VBA是个人小型自动化处理的有效工具。利用好了&#xff0c;可以大大提高自己的工作效率&#xff0c;而且可以提高数据的准确度。我的教程一共九套&#xff0c;分为初级、中级、高级三大部分。是对VBA的系统讲解&#xff0c;从简单的入门&#xff0c;到…

ARPG----C++学习记录03 Section7位置,偏移,函数

Pawn 新建一个Pawn的c类Bird&#xff0c;并且新建一个蓝图 添加一个Capsule&#xff08;胶囊&#xff09; 不知道要加啥头文件&#xff0c;去网站找https://docs.unrealengine.com/5.3/en-US/API/Runtime/Engine/Components/UCapsuleComponent/SetCapsuleSize/ 包含文件名字的头…

【vue3/高德地图】实现地图打点/自定义点位图标/地理围栏实现

<template><div class"app-container"><div id"container"></div></div> </template><script setup> import AMapLoader from amap/amap-jsapi-loader; /*在Vue3中使用时,需要引入Vue3中的shallowRef方法(使用s…

Microsoft Edge浏览器不兼容解决办法

找到 Edge 的安装位置&#xff0c;一般在 C:\Program Files (x86)Microsoft Edge\Application\ 这个目录&#xff0c;把 edge.exe 或msedge.exe 修改为 chrome.exe 再重启电脑。

DocTemplateTool - 可根据模板生成word或pdf文件的工具

你是否经常遇到这样的场景&#xff1a;产品运营有着大量的报告需求&#xff0c;或者给客户领导展现每周的运营报告&#xff1f;这些文档类的任务可以交给运营同事&#xff0c;他们负责文档排版和样式&#xff0c;你作为开发人员你只需要提供数据源&#xff0c;和一个映射表&…

C++ -std 编译标准

概述 任何一门编程语言都有相关的组织和团体在不停的维护和更新。原因很简单&#xff0c;时代在发展&#xff0c;编程语言如果停滞不前&#xff0c;最终就会被淘汰。 以 C 语言为例&#xff0c;发展至今该编程语言已经迭代了诸多个版本&#xff0c;例如 C89 &#xff08;偶尔…

十大字体设计网站年终盘点:顶级设计师独家推荐

即时设计 首款国产的专业 UI 设计工具即时设计&#xff0c;官方字体库内置几十种字体任你选择&#xff0c;例如阿里巴巴惠普体、思源宋体、思源黑体、优设标题黑等&#xff0c;一键点击使用无需下载安装。还能够根据设计内容进行字体粗细调节&#xff0c;从纤细到特粗&#xf…

基准测试详解

&#x1f4e2;专注于分享软件测试干货内容&#xff0c;欢迎点赞 &#x1f44d; 收藏 ⭐留言 &#x1f4dd; 如有错误敬请指正&#xff01;&#x1f4e2;交流讨论&#xff1a;欢迎加入我们一起学习&#xff01;&#x1f4e2;资源分享&#xff1a;耗时200小时精选的「软件测试」资…

柱状图:带误差棒

误差棒可以表示样本标准差&#xff0c;也可以表示样本标准误。 导入库&#xff1a; import pandas as pd 自定义用来绘制带误差棒&#xff08;样本标准差或样本标准误&#xff09;的柱状图&#xff1a; def col(y, x, face, df, errprbarstd) : print(ggplot(df.groupby([x…

el-checkbox-group的全选与反选

需求如下&#xff1a; 思路&#xff1a;在点击全部时按钮组双向绑定赋值全部值&#xff0c;点击按钮组内按钮计算选中按钮数量与按钮组数量对比&#xff0c;判定是否选中全部 代码如下&#xff1a; <template><div><el-checkbox-button v-model"checkall…

视频去水印怎么去?3个简单的去水印方法分享

当我们需要视频去水印怎么去时&#xff0c;了解如何有效地去除视频水印变得至关重要,在日常使用视频资源的过程中&#xff0c;我们可能会遇到一些带有品牌标志或文字水印的视频&#xff0c;这些水印可能会影响视频的观赏体验&#xff0c;特别是当我们需要将视频用于学习、研究或…