部分内容来源:JavaGuide 


select/poll/epoll 和 三种IO模型之间的关系是什么?

区分普通IO和IO多路复用

普通IO,即一个线程对应一个连接,因为每个线程只处理一个客户端 socket,目标明确:线程中直接操作该 socket 的 read() / write(),无需关心其他连接,也就是无需遍历文件描述符

可以理解成,一个线程只持有一个Socket的文件描述符

而IO多路复用是一个线程持有多个Socket的文件描述符,所以它有一个文件描述符集合,内核要遍历这个文件描述集合检查每个Socket中是否有数据


区分select/poll/epoll和三种IO模型

select/poll/epoll 是 如何遍历文件描述符寻找有数据的 Socket 的方法;

IO 模型是Socket 拿到数据后如何处理的策略

IO多路复用是单线程如何高效管理和寻找多个Socket,而IO模型是如何处理多个Socket的数据

并且IO多路复用属于同步IO

Reactor是基于select/epoll这些IO多路复用机制实现的,也就是基于同步IO

Proactor是基于异步IO机制实现的


IO多路复用的演进流程

线程池实现资源复用

如果要让服务器服务多个客户端,那么最直接的方式就是为每一条连接创建线程

其实创建进程也是可以的,原理是一样的

进程和线程的区别在于线程比较轻量级些,线程的创建和线程间切换的成本要小些

为了描述简述,后面都以线程为例

处理完业务逻辑后,随着连接关闭后线程也同样要销毁了,但是这样不停地创建和销毁线程,不仅会带来性能开销,也会造成浪费资源,而且如果要连接几万条连接,创建几万个线程去应对也是不现实的

要这么解决这个问题呢?我们可以使用「资源复用」的方式

通过池化思想保存历史连接

也就是不用再为每个连接创建线程,而是创建一个「线程池」,将连接分配给线程,然后一个线程可以处理多个连接的业务。


线程怎样才能高效地处理多个连接的业务?

当一个连接对应一个线程时,线程一般采用「read -> 业务处理 -> send」的处理流程

如果当前连接没有数据可读,那么线程会阻塞在 read 操作上(socket 默认情况是阻塞 I/O)

不过这种阻塞方式并不影响其他线程。

但是引入了线程池,那么一个线程要处理多个连接的业务,线程在处理某个连接的 read 操作时,如果遇到没有数据可读,就会发生阻塞,那么线程就没办法继续处理其他连接的业务。

要解决这一个问题,最简单的方式就是将 socket 改成非阻塞,然后线程不断地轮询调用 read 操作来判断是否有数据,这种方式虽然该能够解决阻塞的问题

但是解决的方式比较粗暴

因为轮询是要消耗 CPU 的,而且随着一个线程处理的连接越多,轮询的效率就会越低

为什么Socket要设置为非阻塞?

当socket设为非阻塞时,即使没有数据可读,read()也会立即返回一个【无数据的错误】

(如 Linux 的EAGAIN),不会阻塞线程

此时线程可以通过轮询处理多个连接

线程循环遍历自己负责的所有socket描述符,对每个socket调用read()

  1. 如果read()返回数据,就处理该连接的业务;
  2. 如果read()返回 “无数据”,就跳过这个socket,继续轮询下一个

监听连接

上面的问题在于,线程并不知道当前连接是否有数据可读,从而需要每次通过 read 去试探

那有没有办法在只有当连接上有数据的时候,线程才去发起读请求呢?

答案是有的,实现这一技术的就是 I/O 多路复用

I/O 多路复用技术会用一个系统调用函数来监听我们所有关心的连接,也就说可以在一个监控线程里面监控很多的连接


三种IO模型

小区别

IO多路复用属于网络监听模型,例如Redis实现网络监听的时候就是使用IO多路复用的,当Redis启动的时候,它会主动使用IO多路复用网络监听模型去监听

每个 Socket 在内核中都有对应的接收缓冲区发送缓冲区

read:从该 Socket 对应的接收缓冲区中读取数据到用户缓冲区


Reactor 是非阻塞同步网络模式,而 Proactor 是异步网络模式

这里先给大家复习下阻塞、非阻塞、同步、异步 I/O 的概念

阻塞I/O

先来看看阻塞 I/O,当用户程序执行 read,线程会被阻塞

一直等到内核数据准备好,并把数据从内核缓冲区拷贝到应用程序的缓冲区中,当拷贝过程完成,read 才会返回

注意:阻塞等待的是「内核数据准备好」和「数据从内核态拷贝到用户态」这两个过程

过程如下图:


非阻塞 I/O

知道了阻塞 I/O,来看看非阻塞 I/O,非阻塞的 read 请求在数据未准备好的情况下立即返回,可以继续下执行

此时应用程序不断轮询内核直到数据准备好

内核将数据拷贝到应用程序缓冲区,read 才可以获取到结果

过程如下图:

注意,这里最后一次 read 调用,获取数据的过程,是一个同步的过程,是需要等待的过程。这里的同步指的是内核态的数据拷贝到用户程序的缓存区这个过程


异步IO

如果 socket 设置了 O_NONBLOCK 标志,那么就表示使用的是非阻塞 I/O 的方式访问

而不做任何设置的话,默认是阻塞 I/O

因此,无论 read 和 send 是阻塞 I/O,还是非阻塞 I/O 都是同步调用

因为在 read 调用时,内核将数据从内核空间拷贝到用户空间的过程都是需要等待的,也就是说这个过程是同步的,如果内核实现的拷贝效率不高,read 调用就会在这个同步过程中等待比较长的时间

为什么这么说?

同步 的核心是:用户线程必须亲自参与数据拷贝的等待过程

并且用户 线程必须等待拷贝完成才能继续执行

同步IO要等待的两个步骤:

  1. 「内核数据准备好」
  2. 「数据从内核空间拷贝到用户空间」

阻塞IO:等待。你到咖啡店后,发现咖啡还没做好,于是站在柜台前一直等

非阻塞IO:轮询。你到咖啡店后如果没好,那你就去附近晃悠一会儿,然后再问咖啡时候做好了,直到店员说好了


真正的异步 I/O 是「内核数据准备好」和「数据从内核态拷贝到用户态」这两个过程都不用等待

当我们发起 aio_read(异步 I/O)之后,就立即返回,内核自动将数据从内核空间拷贝到用户空间

这个拷贝过程同样是异步的,内核自动完成的

和前面的同步操作不一样,应用程序并不需要主动发起拷贝动作

过程如下图:


理解IO的简单例子

举个你去饭堂吃饭的例子,你好比应用程序,饭堂好比操作系统


阻塞 I/O

你去饭堂吃饭,但是饭堂的菜还没做好,然后你就一直在那里等啊等,等了好长一段时间终于等到饭堂阿姨把菜端了出来(数据准备的过程),但是你还得继续等阿姨把菜(内核空间)打到你的饭盒里(用户空间),经历完这两个过程,你才可以离开。


非阻塞 I/O

你去了饭堂,问阿姨菜做好了没有,阿姨告诉你没,你就离开了,过几十分钟,你又来饭堂问阿姨,阿姨说做好了,于是阿姨帮你把菜打到你的饭盒里,这个过程你是得等待的


异步 I/O

你让饭堂阿姨将菜做好并把菜打到饭盒里后,把饭盒送到你面前,整个过程你都不需要任何等待


很明显,异步 I/O 比同步 I/O 性能更好

因为异步 I/O 在「内核数据准备好」和「数据从内核空间拷贝到用户空间」这两个过程都不用等待

Proactor 正是采用了异步 I/O 技术,所以被称为异步网络模型


简单总结-IO多路复用的演进流程

面试引导:

线程创建销毁的开销

->池化思想

->select,poll存在的问题

->轮询机制对比事件驱动机制

->epoll,基于红黑树和哈希表而不是遍历文件描述符

->引出IO多路复用的两种实现,即Reactor和Proactor


池化思想:

如果让一个服务器能够服务更多的服务端,最直接的方式就是给每一条连接创建一个线程

但是线程的创建和销毁是有一定的开销的,会消耗CPU的时间片轮转的资源

所以为了达到资源复用就出现了【池化思想】,也就是我们的线程池


不要弄混执行任务的线程池和处理IO的线程池,这两个东西只是分别处理的东西不同

线程的职责可以根据任务类型划分

有的线程专注于处理连接的 I/O 操作

有的线程专注于执行业务逻辑任务


IO线程如何高效处理多个连接的业务:

一个连接对应一个线程时线程的处理流程:

「read -> 业务处理 -> send」

线程池的目的是让一个线程照顾多个连接

但一线程对应多连接时,线程在处理某个连接的 read 操作时,如果没有数据可读,则会阻塞

导致线程无法执行其它的IO任务

简单解决方式:将Socket换成非阻塞,之后线程不断地轮询调用 read 操作来判断是否有数据

但轮询是要消耗 CPU 的,随着一个线程处理的连接越多,轮询的效率就会越低

当socket设为非阻塞时,即使没有数据可读,read()也会立即返回一个【无数据的错误】,不会阻塞线程


监听连接:

问题所在:线程并不知道当前连接是否有数据可读

因此需要每次通过 read 去试探(轮询)

我们可以引入一种事件驱动机制,等连接来了我们再去执行,这就是epoll


三种IO模型-快速复习

小区别(防止概念混淆):

IO多路复用属于网络监听模型,例如Redis实现网络监听的时候就是使用IO多路复用的,当Redis启动的时候,它会主动使用IO多路复用网络监听模型去监听

每个 Socket 在内核中都有对应的接收缓冲区发送缓冲区

read:从该 Socket 对应的接收缓冲区中读取数据到用户缓冲区


理解三种IO模型:

read 和 send 是阻塞 I/O,还是非阻塞 I/O 都是同步调用

因为在 read 调用时,内核将数据从内核空间拷贝到用户空间的过程都是需要等待的,也就是说这个过程是同步的,如果内核实现的拷贝效率不高,read 调用就会在这个同步过程中等待比较长的时间

为什么这么说?

同步 的核心是:用户线程必须亲自参与数据拷贝的等待过程

并且用户 线程必须等待拷贝完成才能继续执行

同步IO要等待的两个步骤:

  1. 「内核数据准备好」
  2. 「数据从内核空间拷贝到用户空间」

阻塞IO:等待。你到咖啡店后,发现咖啡还没做好,于是站在柜台前一直等

非阻塞IO:轮询。你到咖啡店后如果没好,那你就去附近晃悠一会儿,然后再问咖啡时候做好了,直到店员说好了


真正的异步 I/O 是「内核数据准备好」和「数据从内核态拷贝到用户态」这两个过程都不用等待

当我们发起 aio_read(异步 I/O)之后,就立即返回

内核自动将数据从内核空间拷贝到用户空间

这个拷贝过程同样是异步的,内核自动完成的

和前面的同步操作不一样,应用程序并不需要主动发起拷贝动作

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

如若内容造成侵权/违法违规/事实不符,请联系英文站点网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Actor-Critic重要性采样原理

目录 AC的数据低效性: 根本原因:策略更新导致数据失效 应用场景: 1. 离策略值函数估计 2. 离策略策略优化 3. 经验回放(Experience Replay) 4. 策略梯度方法 具体场景分析 场景1:连续策略更新 场…

【赠书福利,回馈公号读者】《智慧城市与智能网联汽车,融合创新发展之路》

「5G行业应用」公号作家团队推出《智慧城市与智能网联汽车,融合创新发展之路》。本书由机械工业出版社出版,探讨如何通过车城融合和创新应用,促进汽车产业转型升级与生态集群发展,提升智慧城市精准治理与出行服务效能。&#xff0…

5G NR PDCCH之处理流程

本节主要介绍PDCCH处理流程概述。PDCCH(Physical Downlink Control Channel,物理下行控制信道)主要用于传输DCI(Downlink Control Information,下行控制信息),用于通知UE资源分配,调…

力扣网编程135题:分发糖果(贪心算法)

一. 简介本文记录力扣网上涉及数组方面的编程题:分发糖果。这里使用贪心算法的思路来解决(求局部最优,最终求全局最优解):每个孩子只需要考虑与相邻孩子的相对关系。二. 力扣网编程135题:分发糖果&#xff…

每日mysql

什么是Mysql索引最左匹配原则?最左匹配原则是指,在复合索引中,查询条件需要从左到右和索引开始依次完全匹配的时候,复合索引才可以被有效使用。因为联合索引在建立b树的过程中是根据索引的顺序从左到右进行排序的,所以…

树莓派5-ollama-linux-arm64.tgz 下载

1.下载 由于官方下载速度太慢且容易失败,我这里上传了一份到云盘供大家下载: 通过网盘分享的文件:ollama-linux-arm64.tgz 链接: https://pan.baidu.com/s/1tx_OPpl-8O2HJfXlP4tXTg?pwdffwx 提取码: ffwx --来自百度网盘超级会员v4的分享 …

2024年团体程序设计天梯赛

比赛链接 https://ac.nowcoder.com/acm/contest/80027 A&#xff1a; JMU-1 考察搜索的能力百度一下可知&#xff0c;2024 年天梯赛总决赛的比赛日为4 月 20日 参考代码 //2024 年天梯赛总决赛的比赛日为4 月 20日 void solve(){//A20-7cout<<"H\n"; } B&…

基于CMMI的软件质量管理体系深度解析

核心理念&#xff1a;CMMI&#xff08;Capability Maturity Model Integration&#xff09;是通过过程改进驱动质量提升的体系化框架&#xff0c;其本质是建立可量化、可重复、可优化的工程管理能力一、CMMI体系框架与演进 #mermaid-svg-MdDBl2P8fSHYDHMc {font-family:"t…

2025年渗透测试面试题总结-2025年HW(护网面试) 44(题目+回答)

安全领域各种资源&#xff0c;学习文档&#xff0c;以及工具分享、前沿信息分享、POC、EXP分享。不定期分享各种好玩的项目及好用的工具&#xff0c;欢迎关注。 目录 2025年HW(护网面试) 44 1. SQL注入常用函数 2. SQLMap爆当前库名参数 3. Nmap探测系统参数 4. Nmap小写 …

【操作系统-Day 5】通往内核的唯一桥梁:系统调用 (System Call)

Langchain系列文章目录 01-玩转LangChain&#xff1a;从模型调用到Prompt模板与输出解析的完整指南 02-玩转 LangChain Memory 模块&#xff1a;四种记忆类型详解及应用场景全覆盖 03-全面掌握 LangChain&#xff1a;从核心链条构建到动态任务分配的实战指南 04-玩转 LangChai…

完整 Spring Boot + Vue 登录系统

项目名称&#xff1a;springboot-vue-login-template✅ 功能一览模块功能后端Spring Boot MyBatis Plus JWT Shiro数据库MySQL 用户表前端Vue3 Element Plus Axios登录流程用户名/密码验证 → 返回 Token → 存储 LocalStorage权限控制拦截器校验 Token Shiro 角色权限跨…

Redis 基础详细介绍(Redis简单介绍,命令行客户端,Redis 命令,Java客户端)

1. Redis 简介Redis&#xff08;Remote Dictionary Server&#xff09;是一个开源的内存数据库&#xff0c;遵守 BSD 协议&#xff0c;它提供了一个高性能的键值&#xff08;key-value&#xff09;存储系统&#xff0c;常用于缓存、消息队列、会话存储等应用场景。1.1 特征丰富…

C/C++数据结构之多维数组

概述多维数组&#xff0c;实际上就是“数组的数组”。最常见的是二维数组&#xff0c;就像一个表格&#xff0c;拥有行和列。而三维数组则可以想象为多个这样的表格堆叠起来形成的一个立方体。依此类推&#xff0c;我们可以构建四维、五维甚至更高维度的数组。多维数组主要用于…

[Rust 基础课程]选一个合适的 Rust 编辑器

市面上现在有很多编辑器都可以开发 Rust&#xff0c;很多都是以安装 Rust 插件的形式来对 Rust 做支持&#xff0c;本课程使用 RustRover&#xff0c;如果你喜欢其他的编辑器&#xff0c;可以自己捣鼓下。 RustRover https://www.jetbrains.com/rust/ jetbrains 专门对于 Ru…

【零基础学AI】第37讲:提示词工程(Prompt Engineering)

本节课你将学到 理解提示词工程的核心原理 掌握5种实用的Prompt设计模式 学会优化提示词的评估方法 实现一个智能问答系统优化案例 开始之前 环境要求 Python 3.8安装包&#xff1a;pip install openai tiktokenOpenAI API密钥&#xff08;免费注册&#xff1a;https://plat…

莫兰迪色系工作总结汇报PPT模版分享

莫兰迪色工作总结PPT模版&#xff0c;莫兰迪调色板PPT模版&#xff0c;莫兰迪色系高级简约PPT模版&#xff0c;莫兰迪色系工作汇报&#xff0c;莫兰迪总结汇报模版 莫兰迪色系工作总结汇报PPT模版分享&#xff1a;https://pan.quark.cn/s/35bcaa03c837

uniapp的app项目,某个页面长时间无操作,返回首页

最开始想做成一个公共的&#xff0c;完全提取出来的一个组件&#xff0c;组件设置背景透明&#xff0c;到时候哪个页面需要&#xff0c;直接引入组件就可以了&#xff0c;所以最开始做的是一个vue的组件&#xff0c;在组件中&#xff0c;监听页面的touchstart&#xff0c;但是这…

【实证分析】上市公司绿色战略数据集(2000-2023年)

数据简介&#xff1a;绿色战略是指企业根据其所处的外部环境&#xff08;包括“绿色浪潮”等环保趋势&#xff09;和企业自身的经营条件&#xff0c;为实现企业生存与发展质量的持续提升&#xff0c;而对企业生产经营活动进行绿色化改造的总体规划。这包括制定企业绿色可持续发…

【SpringAI】7. 基于 milvus 的向量检索

SpringAI 基于 milvus 的向量检索 向量数据库可以使用 milvus&#xff0c;redis,Elasticsearch 等&#xff0c;本文以 milvus 为例&#xff1a; 1. 启动milvus 为了尽可能快速上手springai的vectordb功能&#xff0c;我们推荐使用云上的milvus&#xff0c;注册就能创建免费的…

如何使用数字化动态水印对教育视频进行加密?

文章目录前言一、什么是数字化动态水印二、使用数字化动态水印对教育视频加密的好处&#xff1f;三、数字化动态水印的实现原理四、如何实现数字化动态水印对教育视频加密总结前言 教育资源数字化蓬勃发展的今天&#xff0c;优质视频课程已成为机构的核心知识资产。然而&#…