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…...

LBE-LEX系列工业语音播放器|预警播报器|喇叭蜂鸣器的上位机配置操作说明
LBE-LEX系列工业语音播放器|预警播报器|喇叭蜂鸣器专为工业环境精心打造,完美适配AGV和无人叉车。同时,集成以太网与语音合成技术,为各类高级系统(如MES、调度系统、库位管理、立库等)提供高效便捷的语音交互体验。 L…...
基于大模型的 UI 自动化系统
基于大模型的 UI 自动化系统 下面是一个完整的 Python 系统,利用大模型实现智能 UI 自动化,结合计算机视觉和自然语言处理技术,实现"看屏操作"的能力。 系统架构设计 #mermaid-svg-2gn2GRvh5WCP2ktF {font-family:"trebuchet ms",verdana,arial,sans-…...

基于FPGA的PID算法学习———实现PID比例控制算法
基于FPGA的PID算法学习 前言一、PID算法分析二、PID仿真分析1. PID代码2.PI代码3.P代码4.顶层5.测试文件6.仿真波形 总结 前言 学习内容:参考网站: PID算法控制 PID即:Proportional(比例)、Integral(积分&…...

【Oracle APEX开发小技巧12】
有如下需求: 有一个问题反馈页面,要实现在apex页面展示能直观看到反馈时间超过7天未处理的数据,方便管理员及时处理反馈。 我的方法:直接将逻辑写在SQL中,这样可以直接在页面展示 完整代码: SELECTSF.FE…...
三维GIS开发cesium智慧地铁教程(5)Cesium相机控制
一、环境搭建 <script src"../cesium1.99/Build/Cesium/Cesium.js"></script> <link rel"stylesheet" href"../cesium1.99/Build/Cesium/Widgets/widgets.css"> 关键配置点: 路径验证:确保相对路径.…...

解决Ubuntu22.04 VMware失败的问题 ubuntu入门之二十八
现象1 打开VMware失败 Ubuntu升级之后打开VMware上报需要安装vmmon和vmnet,点击确认后如下提示 最终上报fail 解决方法 内核升级导致,需要在新内核下重新下载编译安装 查看版本 $ vmware -v VMware Workstation 17.5.1 build-23298084$ lsb_release…...

PL0语法,分析器实现!
简介 PL/0 是一种简单的编程语言,通常用于教学编译原理。它的语法结构清晰,功能包括常量定义、变量声明、过程(子程序)定义以及基本的控制结构(如条件语句和循环语句)。 PL/0 语法规范 PL/0 是一种教学用的小型编程语言,由 Niklaus Wirth 设计,用于展示编译原理的核…...

PHP 8.5 即将发布:管道操作符、强力调试
前不久,PHP宣布了即将在 2025 年 11 月 20 日 正式发布的 PHP 8.5!作为 PHP 语言的又一次重要迭代,PHP 8.5 承诺带来一系列旨在提升代码可读性、健壮性以及开发者效率的改进。而更令人兴奋的是,借助强大的本地开发环境 ServBay&am…...
Kubernetes 网络模型深度解析:Pod IP 与 Service 的负载均衡机制,Service到底是什么?
Pod IP 的本质与特性 Pod IP 的定位 纯端点地址:Pod IP 是分配给 Pod 网络命名空间的真实 IP 地址(如 10.244.1.2)无特殊名称:在 Kubernetes 中,它通常被称为 “Pod IP” 或 “容器 IP”生命周期:与 Pod …...
[特殊字符] 手撸 Redis 互斥锁那些坑
📖 手撸 Redis 互斥锁那些坑 最近搞业务遇到高并发下同一个 key 的互斥操作,想实现分布式环境下的互斥锁。于是私下顺手手撸了个基于 Redis 的简单互斥锁,也顺便跟 Redisson 的 RLock 机制对比了下,记录一波,别踩我踩过…...