事件驱动模型&IO模型

什么是事件驱动模型?

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

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

实际的现实生活问题

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

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

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

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

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

开发者的实际遇到的问题

拿订单创建的例子来说:

//在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

  • 2
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
### 回答1: Linux IO 模型是指 Linux 操作系统中的 IO 处理机制。它的目的是解决多个程序同时使用 IO 设备时的资源竞争问题,以及提供一种高效的 IO 处理方式。 Linux IO 模型主要分为三种:阻塞 IO、非阻塞 IO 和 IO 多路复用。 阻塞 IO 指的是当程序进行 IO 操作时,会被挂起直到 IO 操作完成,这种方式简单易用,但是对于高并发环境不太适用。 非阻塞 IO 指的是程序进行 IO 操作时,如果无法立即完成,会立即返回一个错误码,程序可以通过循环不断地进行 IO 操作来实现轮询的效果。非阻塞 IO 可以提高程序的响应速度,但是会增加程序的复杂度。 IO 多路复用指的是程序可以同时监听多个 IO 设备,一旦有 IO 事件发生,就会立即执行相应的操作。IO 多路复用可以提高程序的效率,但是需要程序员手动编写代码来实现。 Linux IO 模型还有其他的实现方式,比如信号驱动 IO 和异步 IO 等。但是这些方式的使用比较复杂,一般不常用。 ### 回答2: Linux中的IO模型是指操作系统在处理输入输出的过程中所遵循的一种方式。它主要包括阻塞IO、非阻塞IO、多路复用IO和异步IO四种模型。 阻塞IO是最简单的IO模型,当一个IO操作发生时,应用程序会被阻塞,直到IO操作完成才能继续执行。这种模型的特点是简单直接,但是当有多个IO操作时会造成线程的阻塞,影响系统的性能。 非阻塞IO是在阻塞IO的基础上发展而来的,应用程序在发起一个IO操作后可以继续执行其他任务,不必等待IO操作的完成。但是需要通过轮询来不断地检查IO操作是否完成,效率相对较低。 多路复用IO使用select、poll、epoll等系统调用来监听多个IO事件,当某个IO事件就绪时,应用程序才会进行读写操作,避免了前两种模型的效率问题。多路复用IO模型适用于连接数较多时的场景,如服务器的网络通信。 异步IO是最高效的IO模型,应用程序发起一个IO操作后,立即可以执行其他任务,不需要等待IO操作的完成。当IO操作完成后,操作系统会通知应用程序进行后续处理。异步IO模型常用于高吞吐量、低延迟的应用,如高性能服务器和数据库等。 总之,Linux IO模型提供了多种不同的方式来处理输入输出,每种模型都有其适用的场景和特点。选择合适的IO模型可以提高系统的性能和效率。 ### 回答3: Linux IO模型是指操作系统中用于处理输入输出操作的一种方法或机制。在Linux中,常见的IO模型有阻塞IO、非阻塞IO、IO多路复用和异步IO。 阻塞IO是最基本的IO模型,当应用程序发起一个IO请求时,它将一直阻塞等待直到IO操作完成,期间无法做其他任务。虽然简单易用,但是对资源的利用不高。 非阻塞IO在发起一个IO请求后,不会阻塞等待IO操作完成,而是立即返回并继续做其他任务。应用程序需要不断地轮询IO操作状态,直到操作完成。由于需要不断轮询,对CPU的占用较高,但可以提高资源的利用率。 IO多路复用是通过一个线程同时监听多个IO事件,从而实现并发处理多个IO操作。在IO多路复用模型中,应用程序不需要进行轮询,而是通过调用select、poll或epoll等系统调用监听多个文件描述符的IO事件。这样可以在单个线程中处理多个IO操作,提高并发性能。 异步IO模型在发起一个IO请求后,应用程序不需要等待IO操作完成,而是继续做其他任务。当IO操作完成后,操作系统会通知应用程序。异步IO模型需要操作系统的支持,效率较高,但实现较为复杂。 通过选择合适的IO模型,可以根据不同的应用场景来提高IO操作的效率和性能。例如,对于需要同时处理大量连接的服务器应用,IO多路复用是一种常见的选择;而对于需要处理大量IO操作的高性能服务器,则可以考虑使用异步IO模型

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值