Reactor 和 Proactor模式,IO复用与epoll、同步IO,异步IO与协程
汽车软件中的CPU密集与IO密集任务
在汽车软件中,涉及到ADAS的长期占用CPU的计算任务可以算的上是CPU密集型。
另外的,众多SOA原子服务或者各种数据收集、处理、分发、log系统,应该算是IO密集型任务。
寻求一些手段优化IO性能的原因
在过去开发应用或者中间件时,使用Linux提供的接口,例如直接socket,一般就两种模式,实质上是使用了同步IO:
1、开启循环子线程,阻塞在socket接收处。
2、线程开启循环,周期轮询socket。
这种方式造成了一些弊端,例如对每个socket都需要维护一个子线程,系统给每个线程分配资源造成了资源浪费(如内存)。
虽然阻塞不占用CPU时间,但是如果存在大量socket子线程,线程调度会花费很多CPU时间在进程切换中。造成系统CPU负载率高。
潜在的解决方案
经过研究,一些关键词引起关注。正如本文的标题。
Reactor 和 Proactor模式
Reactor模式和Proactor模式都是基于事件驱动的设计模式,用于处理高并发环境下的I/O多路复用问题。然而,它们在处理I/O事件的方式上有所不同。
Reactor模式是非阻塞同步网络模式,它感知的是就绪可读写事件。具体来说,当某个I/O事件(例如可读就绪)发生时,需要应用进程主动调用相应的read方法来完成数据的读取。这个过程是同步的,即读取完数据后应用进程才能处理数据。因此,Reactor模式可以理解为“来了事件操作系统通知应用进程,让应用进程来处理”。
Proactor模式则是异步网络模式,它感知的是已完成的读写事件。在发起异步读写请求时,需要传入数据缓冲区的地址等信息,这样系统内核才可以自动帮我们把数据的读写工作完成。这里的读写工作全程由操作系统来做,并不需要像Reactor那样还需要应用进程主动发起read/write来读写数据。操作系统完成读写工作后,就会通知应用进程直接处理数据。因此,Proactor模式可以理解为“来了事件操作系统来处理,处理完再通知应用进程”。
总的来说,Reactor和Proactor模式都是基于事件分发的网络编程模式,区别在于Reactor模式是基于“待完成”的I/O事件,而Proactor模式则是基于“已完成”的I/O事件。因此,Proactor模式更加高效,因为它避免了线程间的协作,可以更快地响应I/O事件,但是它的实现相对比较复杂。
IO复用
所谓IO复用,目的是解决前述问题中的每个socket开一个线程的问题。
使用IO复用的机制或者进行IO复用设计(如上文的Reactor模式),使用一个进程监听多个socket。
例如使用一个线程监听多个事件源(如socket),当有事件发生或者可读后,通知对应的程序处理。
落实到Linux内核来帮你做,就变成了Linux IO复用机制,以前有select poll。现在是epoll。
epoll 机制与Reactor
epoll
epoll是Linux下的一个I/O多路复用技术,用于高效地处理大量并发连接。它提供了一组接口,用于注册、修改和删除文件描述符的监听事件。
epoll的接口包括以下几个:
- epoll_create():创建一个新的epoll实例,并返回一个指向它的文件描述符。
- epoll_ctl():注册、修改或删除文件描述符的监听事件。它需要传入epoll实例的文件描述符、文件描述符、事件类型和回调函数。
- epoll_wait():等待注册的文件描述符就绪,并返回就绪的文件描述符列表。它需要传入epoll实例的文件描述符和最大等待时间。
- epoll_pwait():与epoll_wait类似,但是可以设置超时时间,并且可以同时处理多个事件。
使用epoll的一般步骤如下:
- 创建一个epoll实例,获取其文件描述符。
- 使用epoll_ctl()函数注册需要监听的事件和回调函数。
- 在需要处理事件的时候,调用epoll_wait()或epoll_pwait()函数等待事件的发生。
- 处理就绪的事件。
Reactor
Reactor模式是一种事件驱动的设计模式,用于处理高并发环境下的I/O多路复用问题。它由以下几个组件组成:
- Reactor(反应器):是一个接口,定义了注册事件处理器、分发事件和事件处理的方法。通常,Reactor通过异步方式将事件分发给注册的事件处理器。
- Event Handler(事件处理器):是一个接口,定义了事件的回调方法。事件处理器实现了Reactor接口,并注册自己感兴趣的事件类型。当事件发生时,Reactor调用事件处理器的回调方法来处理事件。
- Concrete Event Handler(具体事件处理器):是事件处理器的实现。在其内部实现了事件处理器的回调方法,进行业务逻辑处理。
- Initiation Dispatcher(初始分发器):实际上就是Reactor角色。它本身定义了一些规范,这些规范用于控制事件的调度方式。同时又提供了应用进行事件处理器的注册、删除等操作。它本身是整个事件处理器的核心所在,Initiation Dispatcher会通过Synchronous Event Demultiplexer来等待事件的发生。
工作方式:
- 应用程序创建Reactor对象,并注册感兴趣的事件类型和对应的事件处理器。
- 当事件发生时,Initiation Dispatcher通过Synchronous Event Demultiplexer将事件传递给对应的事件处理器。
- 事件处理器接收到事件后,执行相应的业务逻辑处理。
- 处理完成后,事件处理器会再次注册自己感兴趣的事件类型,以便后续继续处理事件。
可以看出,epoll是一个近似于reactor的实现,或者说,基于epoll机制,可以比较方便的实现一个reactor模式来实现事件驱动程序设计。
我们需要做的是,在epoll 的wait返回后,根据返回的socket 就绪列表,去分发,去调用对应的处理程序。
相较于异步IO来说,在分发的时候这个socket还没有被读取,需要应用程序去读取,但是在调用读取的系统调用的时候,也会存在一个阻塞读取数据,例如从内核态拷贝到用户态的过程,我觉得这对目前的工作来讲已经过于玄学了,车端的应用没互联网那么夸张。
Proactor模式 异步IO Boost.asio 协程
Proactor模式是一种消息异步通知的设计模式,它主要用于处理高并发环境下的I/O多路复用问题。以下是Proactor模式的各个组件及其功能和工作方式:
- Handle句柄:用于标识socket连接或者是打开文件。在网络服务器中,每个客户连接都会创建不同的套接字句柄,当异步连接、读、写操作执行完成时,完成事件会出现在这些句柄上。
- Asynchronous Operation Processor(异步操作处理器):负责执行异步操作,一般由操作系统内核实现。
- Asynchronous Operation(异步操作):这是应用程序发出的服务请求,比如异步的通过套接字句柄读写数据。当异步操作激活后,操作不需要借用回调线程的控制即可执行。因此从回调者角度看,操作的执行是异步的。
- Completion Event Queue(完成事件队列):异步操作完成的结果会放到队列中,等待后续使用。
- Proactor(主动器):为应用程序提供事件循环,从完成事件队列中取出异步操作的结果,分别调用相应的后续处理逻辑。
- Completion Handler(完成事件接口):一般是由回调函数组成的接口。
- Concrete Completion Handler(完成事件处理逻辑):完成接口定义特定的应用处理逻辑。
在业务流程及时序图中,应用程序启动后,会调用异步处理器提供的异步操作接口来发起异步操作。异步操作处理器接收到操作请求后,会执行相应的异步操作。当操作完成后,会将完成事件放入完成事件队列中。Proactor会不断地轮询完成事件队列,一旦发现有完成事件,就会调用相应的回调函数来处理完成事件。
Boost.Asio是一个广泛使用的C++库,用于处理低级网络编程和并发任务。它实现了Proactor模式,提供了一种高效和灵活的方式处理异步I/O操作。
在Boost.Asio中,Proactor模式的应用主要体现在异步I/O操作的处理上。具体来说,当应用程序发起一个异步操作(如异步读或写)时,Boost.Asio会将其封装为一个异步操作对象,并将其注册到异步事件处理器中。
异步事件处理器使用异步事件分发器(Asynchronous Event Demultiplexer)来等待事件完成。当异步操作完成时,完成事件会被放入完成事件队列中。然后,Proactor会调用异步事件分发器,将完成事件返回给其调用者。
在处理完成事件时,Proactor会调用相应的回调函数。
这个回调函数通常是由应用程序通过boost::bind创建的函数对象,用于处理异步操作的结果。
通过这种方式,Boost.Asio实现了高效的异步I/O处理,使得应用程序可以在不阻塞主线程的情况下处理大量的并发连接和请求。同时,Proactor模式还提供了回调函数的方式,使得应用程序可以灵活地处理完成事件,从而实现了异步编程。
据说,底层是epoll。。
异步IO与协程
之前我想过一个问题,异步IO可以在调用IO操作之后先干别的,不用等待。
在同步(按照时间顺序,典型的C编程)方式下,我调用IO,肯定是要IO的数据,如果不等着拿数据,这个时候能干嘛呢。
直到我看到了协程这个东西,豁然开朗(之前也困惑或协程这个在一个进程内跳来跳去执行的东西有什么用)。
协程和异步IO结合,可以进一步优化IO密集任务。
异步IO,实际上就是给各个事件注册处理函数,让程序在各个处理函数之间跳来跳去,就是纯纯用户态的事情了,甚至可以躲在用户进程里不出来,根本没有切换进程开销,岂不美哉。
相关文章:
Reactor 和 Proactor模式,IO复用与epoll、同步IO,异步IO与协程
汽车软件中的CPU密集与IO密集任务 在汽车软件中,涉及到ADAS的长期占用CPU的计算任务可以算的上是CPU密集型。 另外的,众多SOA原子服务或者各种数据收集、处理、分发、log系统,应该算是IO密集型任务。 寻求一些手段优化IO性能的原因 在过去…...
nginx反向代理服务器及负载均衡服务配置
一、正向代理与反向代理 正向代理:是一个位于客户端和原始服务器(oricin server)之间的服务器,为了从原始服务器取得内容,客户端向代理发送一个请求并指定目标(原始服务器),然后代理向原始服务器转交请求并将获得的内容返回给客户…...
【Log4j2】Log4j2最佳实践:Log4j2配置超过7天压缩,超过3个月删除文件的滚动日志,分别定义info文件和error文件,按照每小时存储
目录 Log4j2配置 springboot多环境日志配置 参考资料 Log4j2配置 如果你想要在控制台输出美化的日志信息,你可以使用Log4j2的ConsoleAppender和AnsiColorConverter来实现。下面是相应的配置示例: <Configuration status"WARN"><…...
windows和Linux如何做强制域名解析
首先我们了解两个问题: 一、域名解析是什么? 域名解析是让我们可以通过网站的域名来找到它对应的IP地址,以便更加方便的访问我们所需访问的网站的一种服务。 它通过DNS服务器来进行,我们输入所想要访问的域名,将会通过…...
5G NTN:通信新天地,卫星通信的奇妙探索
导言 嗨,大家好!今天我们要深入了解一项让通信更强大的技术——5G NTN。它和卫星通信结合在一起,为我们带来了通信的新时代。在这篇文章中,我们将用白话文揭示5G NTN和卫星通信的关系,探索这个通信世界的奇妙之旅。 5…...
RabbitMQ的基础使用
/*** 使用rabbitMQ* 1.引用amqp场景 RabbitAutoConfiguration就会自动生效* 2.给容器中自动配置了各种api RabbitTemplate AmqpAdmin CachingConnectionFactory RabbitMessagingTemplate* 所有属性都是 spring.rabbitmq开头* 3.通过注解EnableRabbit使用* 4.监听消息 使用Rabbi…...
使用Uniapp随手记录知识点
使用uniapp随手记录知识点 1 组件内置组件扩展组件 2 vuex状态管理使用流程mapState 辅助函数gettersMutation 1 组件 内置组件 内置组件内主要包含一些基础的view button video scroll-view等内置基础组件,满足基础场景 扩展组件 扩展组件是uniapp封装了一些成…...
Fiber Node的数据结构,以及如何在Reconciliation阶段被使用。
首先,Fiber Node是React用来描述组件树的数据结构,每一个React组件都对应一个Fiber Node。下面是一个Fiber Node的基本结构: const fiber {// 标识这个Fiber Node的类型(函数组件,类组件,DOM节点类型等&a…...
Spring Cloud Alibaba 之 Sentinel
大家好,我是升仔 引言 在微服务架构中,服务之间的依赖错综复杂。一旦某个服务出现问题,很容易引发连锁反应,导致整个系统瘫痪。Sentinel 就是为了解决这类问题而生的。它通过流量控制、熔断降级等机制,保护服务不被过多…...
Jenkins Tutorial
什么是Jenkins Jenkins是一个自动化平台,它允许你使用pipelines去部署应用。它也可以自动化其他任务。 BUILDTESTDEPLOYMENT Jenkins 架构 首先,你拥有一个Master Server,它控制pipelines和安排Build到你的Agent上; 其次&…...
css mask 案例
文章目录 一、基本用法二、图案遮罩二、文字阴影效果三、日历探照灯效果 CSS的mask属性用于定义一个可重复使用的遮罩,可以将其应用到任何可视元素上。这个功能类似于Photoshop中的图层蒙版。通过mask属性,可以创建独特的效果,比如圆形、渐变…...
案例系列:Movielens_预测用户对电影的评分_基于行为序列Transformer的推荐系统
文章目录 简介数据集设置准备数据下载并准备数据框将电影评分数据转换为序列 定义元数据为训练和评估创建 tf.data.Dataset创建模型输入编码输入特征创建一个二叉搜索树模型运行训练和评估实验结论 描述: 使用行为序列Transformer(BST)模型在…...
单词接龙[中等]
一、题目 字典wordList中从单词beginWord和endWord的 转换序列 是一个按下述规格形成的序列beginWord -> s1 -> s2 -> ... -> sk: 1、每一对相邻的单词只差一个字母。 2、对于1 < i < k时,每个si都在wordList中。注意,beg…...
机器人制作开源方案 | 森林管理员
作者:李佳骏、常睿康、张智斌、李世斌、高华耸 单位:山西能源学院 指导老师:赵浩成、郜敏 1. 研究背景 森林作为地球上可再生自然资源及陆地生态的主体,在人类生存和发展的历史中起着不可代替的作用,它不仅能提供…...
Laravel框架使用phpstudy本地安装的composer用Laravel 安装器进行安装搭建
一、首先需要安装Laravel 安装器 composer global require laravel/installer 二、安装器安装好后,可以使用如下命令创建项目 laravel new sys 三、本地运行 php artisan serve 四、 使用Composer快速安装Laravel5.8框架 安装指定版本的最新版本(推荐&a…...
炫酷登录注册界面【超级简单 jQuery+JS+HTML+CSS实现】
一:源码获取 这两天根据需求写了一个比较好看的有动态效果的登录注册切换页面,这里我将源码资源分享给大家,大家可以直接免费下载使用哦,没有 vip 的小伙伴找我私聊发送"登录注册"即可我给你发文件,此登录注…...
2023年国赛高教杯数学建模E题黄河水沙监测数据分析解题全过程文档及程序
2023年国赛高教杯数学建模 E题 黄河水沙监测数据分析 原题再现 黄河是中华民族的母亲河。研究黄河水沙通量的变化规律对沿黄流域的环境治理、气候变化和人民生活的影响,以及对优化黄河流域水资源分配、协调人地关系、调水调沙、防洪减灾等方面都具有重要的理论指导…...
跨国企业传输大文件注意事项和解决方案
随着全球化的推进,越来越多的企业需要在跨国业务合作、项目交付、数据分析等方面展开合作,这就带来了大量大文件的传输需求。大文件传输是指文件大小超过1GB的传输,通常涉及视频、音频、图片、文档、压缩包等多种格式。跨国传输大文件不仅需要…...
【Redis】Redis 的数据类型
有五种常用数据类型:String、Hash、Set、List、SortedSet。以及三种特殊的数据类型:Bitmap、HyperLogLog、Geospatial ,其中HyperLogLog、Bitmap的底层都是 String 数据类型,Geospatial 的底层是 Sorted Set 数据类型。 五种常用…...
QT小技巧 - 使用QMovie进行gif切帧
简介 使用QMovie 将 gif 进行切帧, magick 进行合并代码 QString gifPath "E:\\workspace\\qt\\gif2imgs\\203526qre64haq3ccoobqi.gif"; // 你的图片QMovie movie(gifPath); movie.setCacheMode(QMovie::CacheNone);qDebug() << movie.frameCou…...
【人工智能】神经网络的优化器optimizer(二):Adagrad自适应学习率优化器
一.自适应梯度算法Adagrad概述 Adagrad(Adaptive Gradient Algorithm)是一种自适应学习率的优化算法,由Duchi等人在2011年提出。其核心思想是针对不同参数自动调整学习率,适合处理稀疏数据和不同参数梯度差异较大的场景。Adagrad通…...
R语言AI模型部署方案:精准离线运行详解
R语言AI模型部署方案:精准离线运行详解 一、项目概述 本文将构建一个完整的R语言AI部署解决方案,实现鸢尾花分类模型的训练、保存、离线部署和预测功能。核心特点: 100%离线运行能力自包含环境依赖生产级错误处理跨平台兼容性模型版本管理# 文件结构说明 Iris_AI_Deployme…...
Docker 运行 Kafka 带 SASL 认证教程
Docker 运行 Kafka 带 SASL 认证教程 Docker 运行 Kafka 带 SASL 认证教程一、说明二、环境准备三、编写 Docker Compose 和 jaas文件docker-compose.yml代码说明:server_jaas.conf 四、启动服务五、验证服务六、连接kafka服务七、总结 Docker 运行 Kafka 带 SASL 认…...
《从零掌握MIPI CSI-2: 协议精解与FPGA摄像头开发实战》-- CSI-2 协议详细解析 (一)
CSI-2 协议详细解析 (一) 1. CSI-2层定义(CSI-2 Layer Definitions) 分层结构 :CSI-2协议分为6层: 物理层(PHY Layer) : 定义电气特性、时钟机制和传输介质(导线&#…...
2024年赣州旅游投资集团社会招聘笔试真
2024年赣州旅游投资集团社会招聘笔试真 题 ( 满 分 1 0 0 分 时 间 1 2 0 分 钟 ) 一、单选题(每题只有一个正确答案,答错、不答或多答均不得分) 1.纪要的特点不包括()。 A.概括重点 B.指导传达 C. 客观纪实 D.有言必录 【答案】: D 2.1864年,()预言了电磁波的存在,并指出…...
大语言模型如何处理长文本?常用文本分割技术详解
为什么需要文本分割? 引言:为什么需要文本分割?一、基础文本分割方法1. 按段落分割(Paragraph Splitting)2. 按句子分割(Sentence Splitting)二、高级文本分割策略3. 重叠分割(Sliding Window)4. 递归分割(Recursive Splitting)三、生产级工具推荐5. 使用LangChain的…...
C++ 求圆面积的程序(Program to find area of a circle)
给定半径r,求圆的面积。圆的面积应精确到小数点后5位。 例子: 输入:r 5 输出:78.53982 解释:由于面积 PI * r * r 3.14159265358979323846 * 5 * 5 78.53982,因为我们只保留小数点后 5 位数字。 输…...
Web 架构之 CDN 加速原理与落地实践
文章目录 一、思维导图二、正文内容(一)CDN 基础概念1. 定义2. 组成部分 (二)CDN 加速原理1. 请求路由2. 内容缓存3. 内容更新 (三)CDN 落地实践1. 选择 CDN 服务商2. 配置 CDN3. 集成到 Web 架构 …...
Python Ovito统计金刚石结构数量
大家好,我是小马老师。 本文介绍python ovito方法统计金刚石结构的方法。 Ovito Identify diamond structure命令可以识别和统计金刚石结构,但是无法直接输出结构的变化情况。 本文使用python调用ovito包的方法,可以持续统计各步的金刚石结构,具体代码如下: from ovito…...
Kafka入门-生产者
生产者 生产者发送流程: 延迟时间为0ms时,也就意味着每当有数据就会直接发送 异步发送API 异步发送和同步发送的不同在于:异步发送不需要等待结果,同步发送必须等待结果才能进行下一步发送。 普通异步发送 首先导入所需的k…...
