百度360必应搜狗淘宝本站头条
当前位置:网站首页 > 技术文章 > 正文

从架构师的角度带你把“响应式编程”给一次性搞明白,果然绝绝子

myzbx 2024-12-10 18:26 18 浏览

响应式编程详解

响应式编程是一种基于异步数据流驱动、响应式、使用声明式范式的编程模型,需要遵循一定的响应式编程开发规范,并且有具体的类库实现。响应式编程基于数据流而不是控制流进行业务逻辑的推进。

响应式编程与设计模式

在面向对象编程语言中,响应式编程通常以观察者模式呈现。将响应式流模式和迭代器模式比较,其主要区别是,迭代器基于“拉”模式,而响应式流基于“推”模式。

在命令编程范式中,开发者掌握控制流,使用迭代器遍历“数据”,使用hasNext()函数判断数据是否遍历完成,使用next()函数访问下一个元素。在响应式编程模式中,使用观察者模式,数据由消息发布者(Publisher)发布并通知订阅者(Subscriber),而这种观察者模式本身在基于事件监听机制的响应式系统架构中被广泛使用。Java早期的Swing界面设计也是基于视图事件触发业务响应的系统工作模式。所以,从设计模式的角度讲,响应式编程并不是新鲜事物,只是响应式编程将监听的对象扩展到了更大范围:静态或者动态的Stream数据流,如下图所示。

响应式编程还借鉴了Reactor设计模式,我们通常会在高性能NIO网络通信框架中见到Reactor设计模式的身影,用来实现I/O多路复用。其基本思想是将所有要处理的I/O事件注册到一个中心I/O多路复用器上,同时主线程阻塞在多路复用器上,通过轮询或者边缘触发的方式来处理网络I/O事件。当有新的I/O事件到来或准备就绪时,多路复用器返回并将事件分发到对应的处理器中。Reactor设计模式和响应式编程类似,它们都不主动调用某个请求的API,而是通过注册对应接口,实现事件触发执行,如下图所示。

响应式编程与响应式架构

响应式编程很容易和响应式架构混为一谈。前面我们介绍了响应式宣言中的构建软件架构原则,把符合这些原则的系统称为响应式系统。如果说响应式系统与响应式编程之间具有什么关系,那就是响应式系统的架构风格是响应式的,而响应式编程是实现这个架构风格的最佳实践。从宏观角度看,响应式系统由各种不同组件相互操作、调用组成,共同响应用户请求。响应式系统涉及通信协议、I/O模型、网络传输、数据存储等多方面因素,保障系统在响应力、扩展性、容错、灵活性各方面表现出“实时”“低延迟”“轻量”“健壮”的系统特性。而响应式编程可能是这个大的系统架构下的一部分。另外,响应式系统一般是消息驱动的,而响应式编程是事件驱动的。

消息驱动与事件驱动

响应式宣言指出了两者的区别:“消息驱动”中消息数据被送往明确的目的地址,有固定导向;“事件驱动”是事件向达到某个给定状态的组件发出的信号,没有固定导向,只有被观察的数据。

● 在一个消息驱动系统中,可寻址的接收者等待消息的到来然后响应消息,否则保持休眠状态,消息驱动系统专注于可寻址的接收者。响应式系统更加关注分布式系统的通信和协作以达到解耦、异步的特性,满足系统的弹性和容错性,所以响应式系统更倾向于使用消息驱动模式。

● 在一个事件驱动系统中,通知的监听者被绑定到消息源上。这样当消息被发出时,它就会被调用,所以,响应式编程更倾向于事件驱动。

响应式编程与函数式编程

响 应 式 编 程 同 时 容 易 和 函 数 式 编 程 混 淆 。 函 数 式 编 程(Functional Reactive Programming,FRP)在二十年前就被ConalElliott精确地定义了。在函数式编程中,函数是第一类(firstclass)公民,函数式编程由“行为”和“事件”组成。事件是基于时间的离散序列,而行为是不可变的,是随着时间连续变化的数据。函数式编程与响应式编程相比,它更偏重于底层编码的实现细节。

从Java 8开始,Lambda表达式的引入为Java添加了函数式编程的特性,函数式编程提供了闭包的强大功能。Java中的Lambda表达式通常使用(argument)->(body)语法书写,如下所示:

下面是一些典型的Lambda表达式及其函数式接口:

● Consumer<Integer> c=(int x)->{System.out.println(x)};

● BiConsumer<Integer, String>b=(Integer x, String y)-

>System.out.println(x+":"+y);

● Predicate<String>p=(String s)->{s==null};

在Java 8中新增加了@FunctionalInterface接口,用于指明该接口类型是根据Java语言规范定义的函数式接口。Java 8还声明了一些Lambda表达式可以使用的函数式接口。下面是匿名类和使用函数式编程方式的对比示例。

首先,使用@FunctionalInterface定义一个函数式编程接口。

然后,分别使用内部类和Lambda表达式两种方式执行业务逻辑。

可以看到,在函数式编程中,Lambda表达式允许将一个箭头函数作为参数进行传递,这样的语法表达更加简洁,而本质上由编译器推断并帮助实现转换包装为常规代码。因此,可以用更少的代码来实现相同的功能。而响应式编程的重点是基于“事件流”的异步编程范式,响应式编程通过函数编程方式简化面向对象语言语法的臃肿。响应式编程解决问题的流程是:将一个大的问题拆分为许多独立的小的步骤,而这些小的步骤都可以异步非阻塞地执行;当这些小的子任务执行完,它们会组成一个完整的工作流,并且这个工作流的输入输出都是非绑定的。实现响应式编程的关键就是“非阻塞”,执行线程不会因为竞争一个共享资源而陷入阻塞等待,空耗资源,并且最大化地利用物理资源。

响应式编程与命令式编程模式

响应式编程是一种声明式的编程模型,与之相对应的就是命令模式(线程控制流)的编程模型。大家对命令式编程模式比较熟悉,下面是一段常见的基于命令式编程模式的代码:

上述代码是通过变量的赋值并通过加法计算响应数据之间的对应算数关系结果。但是,这个代码有一个潜在的问题,当我们给这两个变量重新赋值时,第二次的Sum值却没有变化,与我们的期望不符,原因是缺少了执行相加的命令指令。

响应式编程的目的是通过“不可变操作符”固定这种数据,构建数据之间的关系,并正确输出结果,不会因为操作命令的遗忘和缺失导致结果的偏差,造成对应关系和结果错误,下面我们看一下如何使用响应式编程方式来固化这种模式。

下面使用Java 9的Flow API实现两个数的相加功能,按照相同思路,当传入的变量不同时,输出的Sum值也会随着变化,我们把这种对应关系构建为一个声明公式,代码实现如下:

从结果看,响应式编程模式的两次Sum值和输入的数值一致,能够达到预期效果。从这个例子中,我们已经初步接触到了响应式编程中数据源也就是事件发布者(Publisher),还有就是事件的监听回调函数集合——消费者(Subscriber)。消费者会根据next、error、complet触发函数对应关系的执行,以及数据的操作符操作,由于消费者的不可变性,可以根据原生的数据结构生成新的数据结构。相比命令式编程,响应式编程使用操作符表述了一个通用业务执行逻辑,一般可以组合达到预期效果,一般的操作符还包含map、filter、reduce等函数,这里就不再赘述了。

编程范式

“普通的工程师堆砌代码,优秀的工程师优化代码,卓越的工程师简化代码”。

如何写出优雅整洁的代码,不仅是一门学问,也是软件工程的重要一环。在上一节中,我们简单介绍了响应式编程的编程范式,本节我们进一步从开发者的视角、系统的性能、满足用户需求等方面讨论不同编程范式的使用场景和特性优势。

编程范式,又称为编程模型,泛指软件编程过程中使用的编程风格,一般不同的编程范式具有不同的语法特性和差异。目前软件开发技术中常用的典型编程范式有以下几种。

● 命令式编程。

● 面向对象编程。

● 声明式编程。

● 函数式编程。

因为每一个编程范式都有很长的发展历史,在编程语言支持上有不同的标准、组织和语法规范等,本节的目的是希望通过对这些编程范式的介绍,可以帮助我们更好地理解响应式编程范式。

命令式编程

命令式编程是非常传统的软件编程方式,命令式编程由不同的逻辑执行步骤组成,通过一步步指令的执行达到业务逻辑的推进,这种方式也称为过程式编程。命令式编程的执行过程非常符合计算机的执行步骤。C语言是命令式编程的典型代表,它更关注的是机器域底层的内存、指令计算、输入输出。在C语言中,我们经常看到大段的过程式指令、各种if/else/for等控制语句、表达式、数据变量的操作、赋值等指令,这种纯指令开发方式要求开发者对计算机的底层工作原理有非常深刻的理解,而且一个指令出现偏差往往会产生不可预知的错误。同时,命令式编程模式的运维也是难度非常高的。

面向对象编程

面向对象编程可以说是编程领域的一个分水岭,开启了高级程序语言在软件开发上的统治阶段。面向对象编程从问题域出发,将封装、继承、多态的语言特性映射到我们的现实世界。在面向对象编程里,业务问题被抽象成类、接口模板,数据和行为被统一封装在对象内部,作为程序的基本组成单元。面向对象编程范式在提升软件重用性、灵活性和扩展性上比过程式编程更进一步,C++、Java作为面向对象编程语言的代表,屏蔽了机器底层的内存管理和机器域的管理细节。而面向对象编程虽然有较高的开发效率,但是降低了代码的运行效率,这也限制了面向对象编程在性能要求苛刻场景下的应用。

声明式编程

声明式编程受当前“约定优于配置”理念的影响,在软件编程开发领域中被大量应用。声明式编程范式的好处是可以通过声明的方式实现业务逻辑,不需要陷入底层具体的业务逻辑实现细节。声明式编程范式关注的焦点不是采用什么算法或者逻辑来解决问题,而是描述、声明解决的问题是什么。当你的代码匹配预先设定好规则,业务逻辑就会被自动触发执行。

很多标记性语言,如HTML、XML、XSLT,就遵循声明式编程范式,而Spring Boot基于注解方式的编程模型也是声明式编程的一个代表。

Spring框架依赖AOP和IoC编程思想降低了开发者对底层逻辑业务细节的了解程度。例如在Spring Boot中,通过@Transactional注解可以声明一个方法具备事务性的操作,当异常发生时,事务会自动回滚,保证业务逻辑的正常和数据一致性。发生在@Transactional注解背后的实现细节,开发者可以不去关心。

函数式编程

在函数式编程范式中,函数无疑是一等公民,函数式编程最具魅力或者最重要的特性就是不可变性。它的不可变性表现在函数式编程表达式的执行结果,只取决于传入函数的参数序列,不受数据状态变化的影响。

函数式编程中的Lambda在Java 8中被引入,可以看成是两个类型之间的关系:一个输入类型和一个输出类型。Lambda演算就是给Lambda表达式一个输入类型的值,它就可以得到一个输出类型的值。

这个计算过程也是函数式代码对映射的描述,因为函数式代码的抽象程度非常高,所以也意味着函数式代码有更好的复用性。

函数式编程和命令式编程相比,更加关注消息或者数据的传递,而不像命令式编程,关注的是指令控制流。共享数据的状态在多线程环境下会存在资源竞争的情况,往往我们需要把额外的精力投入到冲突地解决、数据状态的维护中。而函数的不可变性保证了数据在传递处理过程中不会被篡改,也不需要依赖外部的锁资源或者状态来维护并发。所以函数式编程在多核处理器中具有天然的并发性,可以最大化地利用物理资源实现并行处理功能。

目前,在JVM体系中,已经出现了越来越多函数式编程范式的语言,例如Scala、Groovy、Clojure等。在当前计算机多核、数据优先、高性能的诉求下,函数式编程具有更广阔的发展前景和未来。然而有利总会有弊,函数式编程的语法相比面向对象编程更晦涩,在大规模工程化的协调配合中,还是需要我们去权衡利弊。因为无论哪种语言范式,本质上都是工具,最终目的都是为业务服务。

本文给大家讲解的内容是响应式微服务架构,响应式编程详解

  1. 下篇文章给大家讲解的内容是响应式微服务架构,响应式技术框架
  2. 觉得文章不错的朋友可以转发此文关注小编;
  3. 感谢大家的支持!

相关推荐

攀升战境S5电竞主机评测:NVIDIA RTX 3060实力助阵,光追游戏走起

此次笔者将为玩家们推荐一款游戏主机——攀升战境S5。该主机是攀升电脑今年力推的游戏装备,主机采用一线品牌配件,特别是在显卡选用上严苛把关,精选GeForceRTX30系列显卡,玩家们大可以放心选购...

慎买-神牛闪光灯兼容性问题:神牛V350&amp;松下S5M2

神牛V350和松下S5M2的兼容性问题。大家好,我是向往闪光灯人像的Fish。国庆期间,我购买了神牛V350闪光灯和神牛X2T引闪器,但这成为了我的噩梦。我原以为客服和松友们说这款闪光灯在松下S5M2...

Acer蜂鸟持续办公一整天(acer 蜂鸟s5)

移动办公在工作节奏日益加快的今天越来越普遍,目前大部分工作无法在手持设备上完成,笔记本依然是移动办公最明智的选择。为了实现移动办公,很多笔记本越做越轻薄,性能也越来越强,而续航却一直没有很大提升。笔者...

职业车手明年会骑什么?2021赛季各大世巡赛车队使用器材一览

新年的钟声即将敲响,意味着充满魔幻色彩的2020年即将过去。受新冠肺炎的影响,2020年的赛季非常不同寻常。因这一原因不得不延迟举行的各种比赛导致许多车队的赞助商无法得到足够曝光,这也间接导致了许多车...

三星部分手机系统升级路线图流出(三星系统在哪升级)

三星包括Note3和S5在内的手机在升级到4.4.2系统之后一直没有什么系统升级的消息,而最近流出的一张三星的系统升级路线图中出现了一共13台手机升级KTU84P(也就是Android4.4.4)...

索尼Xperia Z3配置大曝光:升级并不大

IT之家(www.ithome.com):索尼XperiaZ3配置大曝光:升级并不大索尼明天就会在IFA2014大会上发布其下代旗舰XperiaZ3智能手机,目前网上曝光了其原型机,并且机身背后...

不进反退 三星Exynos 5433只能运行32位模式?

三星GalaxyNote4将带有两个版本,除了国行使用的骁龙805以外,还有三星自家的Exynos5433版本。而这颗SoC的详细信息三星并没有公布,据外媒Anandtech称,他们从源码中确认...

尼康Z6III测评:对比EOS R6 II、A7M4、S5IIX

摄影器材测评网站DPReview刚刚发布了尼康Z6III的完整图文测评,该机获得金奖评级,得分达到91%。以下是该文章的摘录——尼康Z6III核心规格:2400万像素“部分堆栈式”传感器RAW连拍:机...

赛默飞Ion S5首批数据公布,玩爆前任PGMTM系列

北美时间9月1日,赛默飞发布了两款最新的NGS系统IonS5和IonS5XL,旨在提供更加简捷的靶向测序流程。10月29日IonS5测序仪的首批实验数据产生于阜外医院。阜外医院研究人员选用了主...

Excel技巧:快速制作批量文件夹,省时省力,加强工作效率

大家好,如果公司领导要求按人员姓名制作文件夹,以一人一档的形式呈现人员档案,办公人员一个一个制作费时费力,而且效力低下,今天为大家介绍快捷制作批量文件夹的方法下面我们用图片来进行演示操作打开表格,选...

国行、港版、美版Apple watch各版本售价一览

今天凌晨,苹果牌手表正式发布,苹果开始正式进入可穿戴设备领域,除了功能和外观,我相信大家更关心的是价格问题了,小编就将国行、港版、美版的Applewatch售价做一总结,以供参考。国行:美版:港版:...

松下全画幅微单S5和S1到底哪里不一样?

Hello,我是ET,欢迎大家来到我的“相机笔记”。————9月2日晚,松下正式发布了第4款全画幅微单LUMIXS5。这一篇,我们主要来说松下LUMIXS5和LUMIXS1到底有哪些区别...

融会贯通之典范 神舟S7-2021S5评测

便携、性能、续航,这简简单单的六个字道出了这么些年来笔记本电脑的设计方向,可是由于底层技术、模具设计等等原因,这三点并不能很好的融合在一起。虽说闻道有先后,术业有专攻,但能够有一台融会贯通的产品,不是...

三国志战略版:S5赛季装X指南,开荒不是一成不变,需要因地制宜

大家好我是零氪玩家花席,S5赛季已经开始,因为S5赛季的野地阵容和S4赛季没有区别,所以S5赛季开荒相对不难。你在S4有经验,并且多了很多武将和战法,还能用150赛季功勋兑换7500战法点。S5赛季新...

聊聊松下S5M2和S5M2X的区别(松下s5k和s5c有什么区别)

先简单说下哪里不同:12bitRAWHDMI外录支持直接将视频录制到USB-SSD上多了All-Intra和ProRes编码支持有线/无线IP推流,USB网络连接黑化的机身不过要特别强调一下,S5...