事件驱动模型IO模型

news2024/11/30 4:57:45

什么是事件驱动模型?

事件驱动模型是一种计算机编程模型,它通过等待事件的触发,在事件被触发时执行对应的处理函数。这种模型下,程序不再按照严格的顺序执行命令,而是以事件为驱动进行执行。事件驱动模型更适合处理大量事件和复杂的业务场景,并且可以提高系统性能和响应速度。熟悉和运用事件驱动模型在某些场景下可以提高代码的效率和稳定性,同时增加代码的可扩展性。

为什么需要事件驱动模型?

实际的现实生活问题

假如你是一家巧克力作坊的老板,生产出美味的巧克力需要三道

工序:首先将可可豆磨成可可粉,然后将可可粉加热并加入糖变成巧克力浆,最后将巧克力浆灌入模具,撒上坚果碎,冷却后就是成品巧克力了。

最开始的时候,每次研磨出一桶可可粉后,工人就会把这桶可可粉送到加工巧克力浆的工人手上,然后再回来加工下一桶可可粉。你很快就会发现,其实工人可以不用自己运送半成品,于是他在每道工序之间都增加了一组传送带,研磨工人只要把研磨好的可可粉放到传送带上,就可以去加工下一桶可可粉了。 传送带解决了上下游工序之间的“通信”问题以及效率也提高了。

传送带上线后确实提高了生产率,但也带来了新的问题:每道工序的生产速度并不相同。在巧克力浆车间,一桶可可粉传送过来时,工人可能正在加工上一批可可粉,没有时间接收。不同工序的工人们必须协调好什么时间往传送带上放置半成品,如果出现上下游工序加工速度不一致的情况,上下游工人之间必须互相等待,确保不会出现传送带上的半成品无人接收的情况。 怎么解决呢?

答案就是加一个暂存仓库。传送带解决了半成品运输问题,仓库可以暂存一些半成品,解决了上下游生产速度不一致的问题 

开发者的实际遇到的问题

拿订单创建的例子来说:

//在orderService内部定义一个放下

@Transactional(rollbackFor = Exception.class)

public void createOrder(CreateOrderCommand command){

  //创建订单

  Long orderId = this.doCreate(command);

  //发送优惠券

  couponService.sendCoupon(command,orderId);

  //增长积分

  integralService.increase(command.getUserId,orderId);

}

业务需求在不断迭代的过程中,与当前业务非强相关的主流程业务,随时都有可能被替换或者升级。

遇到促销之类的,用户下单的同时需要给每个用户赠送几个小礼品,那你又要写一个方法了,追加到后面,订单逻辑会变得越来越长。

事件驱动模型改造

//在orderService内部定义一个放下

@Transactional(rollbackFor = Exception.class)

public void createOrder(CreateOrderCommand command){

  //创建订单

  Long orderId = this.doCreate(command);

  publish(orderCreateEvent);

}

//各个需要监听的服务

public void handlerEvent(OrderCreateEvent event){

//逻辑处理

}

代码解耦、之后基本只需要横向扩展。

事件驱动模型的优点

1. 并发处理:事件驱动模型可以处理多个事件同时发生的情况,而普通模型则需要按照先后顺序一个一个地处理。

2. 响应快速:事件驱动模型能够迅速响应事件的发生,而普通模型可能需要等待某些步骤完成才能进行下一步操作。

3. 易于维护和扩展:事件驱动模型中的代码更易于组合和重用,也更容易实现新的功能或扩展现有功能。

4. 资源利用高效:事件驱动模型中只有在事件发生时才会使用资源,否则资源保持空闲。而普通模型则可能会一直占用资源,浪费系统资源。具体体现? 想一下秒杀的场景

确定请求的秒杀结果后,就可以马上给用户返回响应,然后把请求的数据放入消息队列中,由消息队列异步地进行后续的操作。这样不仅响应速度更快,并且在秒杀期间,我们可以把大量的服务器资源用来处理秒杀请求。秒杀结束后再把资源用于处理后面的步骤,充分利用有限的服务器资源处理更多的秒杀请求。

事件驱动模型的例子

1、操作系统: IO模型的 阻塞、非阻塞IO、IO多路复用。(楼下买饭)。select、poll、epoll的区别?。 真正的AIO(送货上门)。

阻塞IO: 就是你早上去公司楼下买饭,发现排队的人多或者饭没有做好,你就得一直等着饭做好你才走,期间你是不能额外做其他事情的。

非阻塞IO:就是你早上去公司楼下买饭,发现排队的人多或者饭没有做好,你先到公司打个卡,每隔一段时间你就去买饭的地方看下你的早饭好了没。

IO多路复用:就是你早上去公司楼下买饭,发现排队的人多或者饭没有做好,你们公司也意识到存在这种情况,为了员工更好的健康着想(工作效率(手动狗头)),每天会派一个人在饭店等着,这个人记录了一份你们公司所有买早餐的人员名单,然后这个人会按照人员名单不断地问老板,谁的饭做好了就会通知对应的人来取。

AIO: 就是你早上去公司楼下买饭,发现排队的人多或者饭没有做好, 但是饭店提供了一根极致的服务可以送货上门,饭做好后直接送到你的工位,在此期间你就可以愉快的去公司打卡工作了,也不用再亲自去取饭了。

阻塞IO模型

非阻塞IO模型

IO多路复用-select

IO多路复用-epoll

真正的A

select,poll实现需要自己不断轮询所有fd集合,直到设备就绪,期间可能要睡眠和唤醒多次交替。而epoll其实也需要调用epoll_wait不断轮询就绪链表,期间也可能多次睡眠和唤醒交替,但是它是设备就绪时,调用回调函数,把就绪fd放入就绪链表中,并唤醒在epoll_wait中进入睡眠的进程。虽然都要睡眠和交替,但是select和poll在“醒着”的时候要遍历整个fd集合,而epoll在“醒着”的时候只要判断一下就绪链表是否为空就行了,这节省了大量的CPU时间。这就是事件驱动回调机制带来的性能提升。

2、分布式消息系统:kafka、RocketMQ。

带来的问题:

  • 引入消息队列带来的延迟问题;
  • 增加了系统的复杂度;
  • 可能产生数据不一致的问题。
  • 幂等、事务

3、Apache EventMesh等。 

3、单机系统:java原生、spring内置的事件机制、Guava。

带来的问题:

  • 业务逻辑难以直观看到
  • 事件驱动模型通常涉及大量的事件和事件处理程序之间的交互。这可能会导致代码变得复杂和难以理解,因为不同的事件处理程序可能会产生意想不到的副作用和相互作用。

Spring框架中的事件驱动模型实际应用

Spring框架中提供了一套完善的事件机制,可以自定义事件,注册监听器,并在事件被触发时执行对应的处理函数。在Spring框架中,可以通过ApplicationContext对象的publishEvent()方法来发布自定义的事件。当事件被发布后,所有已注册的监听器都会接收到该事件并进行处理。

1. 自定义事件类

可以通过继承ApplicationEvent类来自定义一个事件类,然后在合适的位置使用ApplicationContext发布该事件。

public class MyEvent extends ApplicationEvent {

private String message;

public MyEvent(Object source, String message) {

super(source);

this.message = message;

}

public String getMessage() {

return message;

}

}

2. 定义监听器

事件监听器是一个普通的Java类,负责处理特定事件的逻辑。需要实现ApplicationListener接口,并指定监听的事件类型。当监听器注册到ApplicationContext中时,它会自动接收来自ApplicationContext发布的事件,并执行对应的处理函数。

@Component

public class MyEventListener implements ApplicationListener<MyEvent> {

@Override

public void onApplicationEvent(MyEvent event) {

String message = event.getMessage();

// 处理事件

}

}

也可以使用@EventListener注解来注册监听器并指定其监听的事件类型。

@Component

public class MyEventListener {

@EventListener

@Async

public void handleMyEvent(MyEvent event) {

String message = event.getMessage();

// 处理事件

}

}

3. 发布事件

@Autowired

private ApplicationEventPublisher applicationEventPublisher;

...

applicationEventPublisher.publishEvent(new MyEvent(this"Hello World!"));

以上例子中,首先自定义了一个MyEvent类作为事件模型,在MyEventListener类中实现了ApplicationListener接口,并重写了onApplicationEvent()方法来处理MyEvent事件。在配置文件中注册 MyEventListener 监听器,或者使用@EventListener注解,并通过ApplicationContext对象的publishEvent()方法来发布自定义事件。

事件监听器默认是同步阻塞的。如果同一个事件有多个监听器?如何指定监听器顺序?@Order(1)

4.开启异步

启动类增加此注解 @EnableAsync

监听方法上面增加注解 @Async

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

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

相关文章

[RSA议题分析] Finding Vulnerabilities through Static Analysis and Scripting

文章目录 简介议题分析发现漏洞 - 什么时候/为什么什么是漏洞挖掘漏洞价值 如何挖洞逆向工程环境从哪开始挑战 总结 简介 作者讲了挖漏洞的目标&#xff0c;和一些常用的挖漏洞的方法和如果你像现在开始挖掘二进制漏洞&#xff0c;那么你可以从memcpy开始。除此之外&#xff0…

【SpringBoot系列】Spring EL表达式的简介和快速入门

介绍 Sping EL&#xff08;Spring Expression Language 简称 SpEL&#xff09;是一种强大的表达式语言&#xff0c;支持在运行时查询和操作对象&#xff0c;它可以与 XML 或基于注解的 Spring 配置一起使用。语言语法类似于统一 EL&#xff0c;但提供了额外的功能,方法调用和字…

springboot+vue藏区特产销售平台(java项目源码+文档)

风定落花生&#xff0c;歌声逐流水&#xff0c;大家好我是风歌&#xff0c;混迹在java圈的辛苦码农。今天要和大家聊的是一款基于springboot的藏区特产销售平台。项目源码以及部署相关请联系风歌&#xff0c;文末附上联系信息 。 &#x1f495;&#x1f495;作者&#xff1a;风…

产品经理如何使用集简云实现工作流程自动化?

场景描述 作为一名产品经理&#xff0c;需要每天面对来自各个部门的需求&#xff0c;平时的工作内容更是复杂繁琐&#xff0c;画流程图、产品开发周期、产品描述、设计团队协作&#xff0c;新产品培训会、用户需求会&#xff0c;或跟进 bug 修复等等等等…… 对内不仅要参与业…

STM32与ESP32下载器设计

文章目录 背景STM32下载器使用现成的DAPlink选择自制DAPlink ESP32/ESP8266下载器连接接口STM32接口ESP32接口 背景 我们常用的单片机主要有STM32和ESP32&#xff0c;其中STM32下载要求SWD下载接口&#xff0c;ESP32下载要求串口&#xff0c;但需要控制ESP32 IO0和EN口高低电平…

前端人必须掌握的抓包技能(原理到实践)

目录 1. 前言 2. 抓包的原理 2.1 什么是抓包&#xff1f; 2.2 HTTP/HTTPS 抓包原理 2.2.1 HTTP 抓包原理 2.2.2 HTTPS 抓包原理 2.3 电脑如何抓手机的包 3. 抓包工具 whistle 3.1 whistle 是什么 如何快速使用 whistle 3.2 whistle 可以做的事情 4. whistle 实战案…

HP打印机网络连接扫描仪失败

财务反映,使用主机上的HP LaserJet Pro M329-HP Scan连接扫描仪提示失败。 测试果然失败,提示如下图: 点击修复后,提示 需要安装HP Print and Scan Doctor。 同意安装,并启动HP Print and Scan Doctor 点击开始,其开始搜索,过程有点慢。 第一次发现其连接错误,居然…

液晶显示常用概念

文章目录 数字液晶显示消隐区水平&#xff08;行&#xff09;消隐 HBlank垂直&#xff08;场&#xff09;消隐 VBlank RGB格式RGB555RGB565RGB888 VGA驱动原理时钟信号像素时钟同步信号DE信号&#xff08;有效数据选通信号&#xff09;DE信号与其他信号的关系 数字液晶显示消隐…

golang webhook源码和案例配合gitee实践

下载golang webhook源码和案例&#xff1a; https://download.csdn.net/download/qq_32421489/87824180 解压后go mod tidy下载依赖包 修改打包环境为Linux&#xff1a; go env -w GOOSlinux 打包命令&#xff1a;go build 打包后的可运行程序上传服务器后&#xff1a;参…

用本地连接集群进行压力测试,让你的测试更快更有效!

目录 引言 背景 详细步骤 1、首先打开终端 2、安装kubectl 3、配置kubeconfig 4.准备本地仓库文件 5.启动集群执行脚本 总结 引言 测试是软件开发中至关重要的一环&#xff0c;但长时间的等待和低效率的测试却常常让人感到烦躁。现在&#xff0c;我们推出了全新的解决…

真的裂开了呀,现在的00后,真是卷死了

谁说00后躺平了&#xff0c;但是有一说一&#xff0c;该卷的还是卷。这不&#xff0c;上个月我们公司来了个00后&#xff0c;工作没两年&#xff0c;跳槽到我们公司起薪22K&#xff0c;都快接近我了。 后来才知道人家是个卷王&#xff0c;从早干到晚就差搬张床到工位睡觉了。 …

7个简单步骤创建企业邮箱教程

创建企业邮箱电子邮件地址有几种不同的方法&#xff0c;可以使用电子邮件服务提供商&#xff0c;也可以使用电子邮件托管服务。由于Zoho Mail是世界上最受欢迎的电子邮件服务提供商之一&#xff0c;提供非常简单的帐户设置、大量功能和有竞争力的价格&#xff0c;我们将以它为例…

【敲敲云】免费的零代码产品 — 应用创建与设置

敲敲云可以创建不同的应用&#xff0c;每一个应用我们可以看做一个系统&#xff0c;例如销售系统、财务系统等等。下面我们来看看如何创建应用吧。 应用的基础操作&#xff1a; 应用的基础操作包含创建应用、修改应用、退出/删除应用、排序应用、维护应用、应用回收站 1、新建…

提前进入行业顶尖阵营:高性能计算实习的竞争优势

如今就业越来越内卷&#xff0c;尤其是计算机行业更是如此。加上GPT以及大模型的加持&#xff0c;各大企业纷纷降本增效&#xff0c;普通程序员逐渐失去竞争力。想要在竞争激烈的就业市场中脱颖而出&#xff0c;提前进入行业顶尖阵营是一个明智的选择。而高性能计算实习将为您提…

js中获取对象属性值(对象.属性和对象[属性]的区别)

一、在JavaScript中可以通过两种方式访问对象属性 (1)可以使用“ . ”来访问对象的属性。 (2)可以使用“ [ ] ”来访问对象的属性。 二、对象.属性和对象[属性]的区别&#xff1a; 1.相同点&#xff1a; &#xff08;1&#xff09;都可以获取对象的属性值&#xff1b; 2.不同…

C Primer Plus第七章编程练习答案

学完C语言之后&#xff0c;我就去阅读《C Primer Plus》这本经典的C语言书籍&#xff0c;对每一章的编程练习题都做了相关的解答&#xff0c;仅仅代表着我个人的解答思路&#xff0c;如有错误&#xff0c;请各位大佬帮忙点出&#xff01; 1.编写一个程序读取输入&#xff0c;读…

PID算法在流量控制中的应用

目录 增量式或位置式 目录 增量式或位置式 PID控制周期 T1 时间 T2 约4ms PID C代码 最近有小伙伴向我提问关于PID的问题&#xff1a;通过比例阀控制水流速度&#xff08;流量&#xff09;&#xff0c; 使用增量式还是位置式 PID&#xff1f;他的比例法驱动频率是500Hz…

Windows http https的搭建

目录 搭建http站点 ​编辑 报错 网站端口更改 可能存在的报错 绑定主机名 端口为80的情况下 绑定的端口不为80的情况下 https站点搭建 CA机构证书可以给其他服务器使用&#xff0c;不过要用导出导入的行书&#xff0c;不能直接使用cer文件 搭建http站点 ①勾选IIS ②一…

windows下nginx+tomcat配置负载均衡的方法

在负载均衡方面&#xff0c;Nginx和Tomcat的实现方式略有不同。Nginx作为反向代理服务器&#xff0c;可以直接处理并分发请求到后端服务器&#xff0c;包括Tomcat。它可以使用不同的负载均衡算法来分发请求&#xff0c;将负载均衡的任务集中在Nginx上。而Tomcat通常通过与Apach…

RL Note 1, Basic Concepts in Reinforcement Learning

Basic Concepts in Reinforcement Learning A grid-world example 在该图中&#xff1a; 格子被分为三类&#xff1a;可访问的格子、禁止访问的格子、目标格子角色被称为 agentagent 的任务就是从 start 开始找到一条“正确”的路径到达 targetagent 无法越过边界&#xff0c…