【I/O】基于事件驱动的 I/O 模型---Reactor

2024-04-11 06:12
文章标签 模型 事件驱动 reactor

本文主要是介绍【I/O】基于事件驱动的 I/O 模型---Reactor,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

Reactor 模型

BIO 到 I/O 多路复用

为每个连接都创建一个线程

假设我们现在有一个服务器,想要对接多个客户端,那么最简单的方法就是服务端为每个连接都创建一个线程,处理完业务逻辑后,随着连接关闭线程也要销毁,但是这样线程创建和销毁,不仅会带来性能开销也会带来资源浪费,如果同时有几万个连接,创建几万个线程是不现实的。

使用线程池优化

我们很容易想到使用线程池来优化,也就是不再为每个连接都创建一个线程,而是创建一个「线程池」,将连接分配给线程,然后一个线程可以处理多个连接业务,不过这样的话又会有一个新的问题,当一个连接对应一个线程的时候,线程的处理流程一般是 read -> 业务处理 -> send,当没有数据可读的时候,线程会阻塞在 read 上,所以我们在使用线程池的时候,如果某个线程阻塞在了 read 上,它是没有办法继续处理其他连接的业务。

要解决这一问题,我们需要将连接改为「非阻塞」的,然后线程不断轮询调用 read 操作来查看是否有数据可读,但是轮询也是需要消耗 CPU 的,同时一个线程管理的连接越多轮询的消耗也就越大。

I/O 多路复用

线程池带来的问题在于,线程不知道当前连接是否有数据可读,因此需要不断的轮询进行 read 操作去检测哪个连接有数据可读。I/O 多路复用可以很好的解决这一问题,I/O 多路复用使得只有当连接上有数据的时候,才去发起 read 操作,I/O 多路复用会用一个系统调用函数(select() poll() epoll() )来监听我们所关心的连接,通过系统调用可以从内核中获取多个事件。

在获取事件时,先把我们关心的连接发送个内核,在有内核进行检测:

  • 如果没有事件发生,线程只需要阻塞这个系统调用,而无需像前面的线程池方案那样轮询调用 read 操作
  • 如果有事件发生,内核会返回产生了事件的连接,线程就会从阻塞状态返回,然后在用户态再处理这些连接的业务即可

Reactor 模型

Reactor 模型: I/O 多路复用监听事件,收到事件后,根据事件类型分配给某个线程

Reactor 主要由 Reactor 和 处理资源池 两个核心部分组成:

  • Reactor 负责监听和分发事件,事件包括连接事件、读写事件
  • 处理资源池负责处理事件,如 read -> 业务处理 -> send

单 Reactor 单线程

三个对象 Reactor、Acceptor、Handler

  • Reactor 对象的作用是监听和分发事件
  • Acceptor 对象的作用是获取连接
  • Handler 对象的作用是处理业务

在这里插入图片描述

select、accept、read、send 是系统调用函数,dispatch 是事件分发操作

流程:

  • Reactor 对象通过 select 监听事件,收到事件后通过 dispatch 进行分发
  • 如果事件是建立连接的事件,则交由 Acceptor 对象进行处理,Acceptor 对象会通过 accept 方法获取连接,并将连接注册到 select 上,然后创建一个 Handler 对象来处理后续的响应事件
  • 如果不是连接创建事件,则交由对应的 Handler 对象来进行处理
  • Handler 对象通过 read -> 业务处理 -> send 的流程来完成完整的业务流程

单 Reactor 单线程方案,所有的工作都在一个线程上完成,实现简单,但有两个缺点:

  • 只有一个线程,无法利用多核 CPU 的优势
  • Handler 对象在业务处理时,整个线程无法处理其他连接的事件,如果业务耗时比较长的话,会出现响应延迟

单 Reactor 多线程

在这里插入图片描述

流程:

  • Reactor 对象通过 select 监听事件,收到事件后通过 dispatch 分发事件
  • 如果是连接事件,则将其分发给 Acceptor 对象进行处理,Acceptor 对象通过 accept 方法获取连接,并将连接注册到 select ,然后创建一个 Handler 对象来处理后续的响应事件
  • 如果不是创建连接事件,则交由对应的 Handler 对象进行处理
  • Handler 对象不再进行业务处理,只负责数据的接收和发送,Handler 对象通过 read 方法读取连接中的数据后,会将数据发送给子线程里的 Processor 对象进行业务处理
  • 子线程的 Processor 对象就进行业务处理,业务处理完成后,将结果发送给主线程中的 Handler 对象,接着由 Handler 对象负责将结果使用send方法发送给客户端

单 Reactor 多线程方案能够充分利用多核 CPU 的能力,但是即使业务处理是采用线程池多线程的进行,但是最后还是要靠主线程的 Handler 进行发送,这就带来了 多线程共享数据竞争 的问题,要避免这个问题就不得不在访问共享数据是加上互斥锁,来保证在任一时间内只有一个线程访问共享数据。

单 Reactor 单线程方案还有一个问题,一个 Reactor 担任事件的监听和分发任务,而且是在主线程中进行的,在面对瞬时间的高并发场景,很容易成为性能的瓶颈

多 Reactor 多线程

在这里插入图片描述

流程:

  • 主线程的 MainReactor 通过 select 只监听建立连接事件,收到事件后交给 Acceptor 对象,Acceptor 对象通过 accept 获取连接,随后 MainReactor 将新的连接分配给某个子线程
  • 子线程的 SubReactor 对象将主线程分配的连接注册到 select 上继续进行监听,并创建一个 Handler 对象进行后续连接的响应事件
  • 如果有新的事件发生,SubReactor 会调用对应连接的 Handler 进行事件响应
  • Handler 对象通过 read -> 业务处理 -> send 的流程来完成完整的业务流程

优点:

  • 主线程和子线程分工明确,主线程只负责接收新连接,子线程负责负责监听连接的读写事件以及后续的业务处理
  • 主线程和子线程的交互也很简单,主线程只需要把新的连接传递给子线程,子线程无需返回数据,直接可以在子线程中完成数据的处理和发送给客户端

这篇关于【I/O】基于事件驱动的 I/O 模型---Reactor的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/893279

相关文章

0基础租个硬件玩deepseek,蓝耘元生代智算云|本地部署DeepSeek R1模型的操作流程

《0基础租个硬件玩deepseek,蓝耘元生代智算云|本地部署DeepSeekR1模型的操作流程》DeepSeekR1模型凭借其强大的自然语言处理能力,在未来具有广阔的应用前景,有望在多个领域发... 目录0基础租个硬件玩deepseek,蓝耘元生代智算云|本地部署DeepSeek R1模型,3步搞定一个应

Deepseek R1模型本地化部署+API接口调用详细教程(释放AI生产力)

《DeepseekR1模型本地化部署+API接口调用详细教程(释放AI生产力)》本文介绍了本地部署DeepSeekR1模型和通过API调用将其集成到VSCode中的过程,作者详细步骤展示了如何下载和... 目录前言一、deepseek R1模型与chatGPT o1系列模型对比二、本地部署步骤1.安装oll

Spring AI Alibaba接入大模型时的依赖问题小结

《SpringAIAlibaba接入大模型时的依赖问题小结》文章介绍了如何在pom.xml文件中配置SpringAIAlibaba依赖,并提供了一个示例pom.xml文件,同时,建议将Maven仓... 目录(一)pom.XML文件:(二)application.yml配置文件(一)pom.xml文件:首

如何在本地部署 DeepSeek Janus Pro 文生图大模型

《如何在本地部署DeepSeekJanusPro文生图大模型》DeepSeekJanusPro模型在本地成功部署,支持图片理解和文生图功能,通过Gradio界面进行交互,展示了其强大的多模态处... 目录什么是 Janus Pro1. 安装 conda2. 创建 python 虚拟环境3. 克隆 janus

本地私有化部署DeepSeek模型的详细教程

《本地私有化部署DeepSeek模型的详细教程》DeepSeek模型是一种强大的语言模型,本地私有化部署可以让用户在自己的环境中安全、高效地使用该模型,避免数据传输到外部带来的安全风险,同时也能根据自... 目录一、引言二、环境准备(一)硬件要求(二)软件要求(三)创建虚拟环境三、安装依赖库四、获取 Dee

DeepSeek模型本地部署的详细教程

《DeepSeek模型本地部署的详细教程》DeepSeek作为一款开源且性能强大的大语言模型,提供了灵活的本地部署方案,让用户能够在本地环境中高效运行模型,同时保护数据隐私,在本地成功部署DeepSe... 目录一、环境准备(一)硬件需求(二)软件依赖二、安装Ollama三、下载并部署DeepSeek模型选

Golang的CSP模型简介(最新推荐)

《Golang的CSP模型简介(最新推荐)》Golang采用了CSP(CommunicatingSequentialProcesses,通信顺序进程)并发模型,通过goroutine和channe... 目录前言一、介绍1. 什么是 CSP 模型2. Goroutine3. Channel4. Channe

Python基于火山引擎豆包大模型搭建QQ机器人详细教程(2024年最新)

《Python基于火山引擎豆包大模型搭建QQ机器人详细教程(2024年最新)》:本文主要介绍Python基于火山引擎豆包大模型搭建QQ机器人详细的相关资料,包括开通模型、配置APIKEY鉴权和SD... 目录豆包大模型概述开通模型付费安装 SDK 环境配置 API KEY 鉴权Ark 模型接口Prompt

大模型研发全揭秘:客服工单数据标注的完整攻略

在人工智能(AI)领域,数据标注是模型训练过程中至关重要的一步。无论你是新手还是有经验的从业者,掌握数据标注的技术细节和常见问题的解决方案都能为你的AI项目增添不少价值。在电信运营商的客服系统中,工单数据是客户问题和解决方案的重要记录。通过对这些工单数据进行有效标注,不仅能够帮助提升客服自动化系统的智能化水平,还能优化客户服务流程,提高客户满意度。本文将详细介绍如何在电信运营商客服工单的背景下进行

Andrej Karpathy最新采访:认知核心模型10亿参数就够了,AI会打破教育不公的僵局

夕小瑶科技说 原创  作者 | 海野 AI圈子的红人,AI大神Andrej Karpathy,曾是OpenAI联合创始人之一,特斯拉AI总监。上一次的动态是官宣创办一家名为 Eureka Labs 的人工智能+教育公司 ,宣布将长期致力于AI原生教育。 近日,Andrej Karpathy接受了No Priors(投资博客)的采访,与硅谷知名投资人 Sara Guo 和 Elad G