当前位置: 首页 > news >正文

初识Linux · 五种IO模型和非阻塞IO

目录

前言:

五种IO模型

什么是IO

IO模型

非阻塞IO


前言:

前文我们已经将网络的基本原理介绍完了,都是通过围绕TCP/IP四层协议,将应用层,传输层,网络层,数据链路层全部介绍完毕,至于部分小主题,比如ARP欺骗,HTTP协议的原理,cookie以及session等内容,我们放在后面介绍。

本文以及之后的内容,主要通过是介绍IO相关的问题,通过IO模型的介绍,从而引出多路复用的具体内容,通过介绍select,poll,epoll,最后再单独介绍一下Reactor,网络的基本原理我们就介绍完了。

那么废话不多说,我们直接进入五种IO模型。


五种IO模型

什么是IO

对于IO这个话题,我们从语言阶段,一直到了现在都经常谈论,因为IO问题不管在哪个阶段都是非常重要的,从C语言阶段的printf scanf,到文件操作的read和write涉及到了IO,即便是Linux,我们从一开始的文件系统,引出了文件描述符,到后面的网络也是一直使用文件描述符的概念,足以看出IO在编程中的重要性了。

那么问题来了,一开始我们只是粗略的将IO认定为是输入输出,今天我们进一步探讨,当我们第一次使用scanf的时候,我们发现只要我们不输入,系统就会阻塞住,系统在干什么呢?

系统在等我们输入,所以IO有一个非常重要的过程是:等待。当我们输入数据之后,系统也收到了数据也就不再等待,就执行了下一步操作了。这个过程还有读取的操作,或者是写入的操作,但是不管怎么说,都是从发送缓冲区/接收缓冲区拷贝数据到应用层的缓冲区。

所以实际上的IO = 等待 + 拷贝

而我们从一开始的学习到现在,使用到的基本上都是阻塞IO,自然也就存在非阻塞的IO,我们放在IO模型里面介绍。那么我们在MySQL中介绍索引的时候,我们提及到了IO次数如果多了,就一定会降低效率,所以我们就要使用高效的IO,那么高效的IO实际上减少了等待操作在IO中的比例

IO模型

对于IO模型我们拿钓鱼举例子,假设有五个人,分别在鱼塘中钓鱼,张三拿个鱼竿就坐在那里一直等待,当别人问他什么事,他也不理睬,这是第一种IO模型;李四拿个鱼竿放在那里,就不管了,转身去做自己的事儿了,然后定期来查看鱼竿的情况,这是第二种IO模型;王五拿个鱼竿,钓鱼的时候放个铃铛,当鱼上钩了,就放在自己手里的事儿,然后钓鱼,这是第三种IO模型;赵六就很有说法了,拿了一卡车的鱼竿过来了,同时使用很多的鱼竿,然后一个一个的检查鱼竿情况,这是第四种IO模型;田七的钓鱼操作是派遣一个人,让这个人像张三一样,完成钓鱼的等待和钓操作,自己就转身去干其他事儿了,也就是田七只负责吃的操作,这是第五种IO模型。

那么上述都是一个口语化的介绍,实际上的名称叫做:
第一种,阻塞IO,比如我们常见的read recvfrom scanf都是阻塞IO的代表,如果系统的数据还没有准备好,强行非阻塞的话就会返回错误码11,一会儿我们可以实验。

第二种,非阻塞IO,非阻塞IO顾名思义,IO的同时干自己的事儿,那么这意味着需要反反复复的尝试读写文件描述符,这个过程称为轮询,但是因为会反反复复的操作文件操作符,所以会对CPU资源造成较大的浪费,一般根据特定情况使用:

第三种,信号驱动IO,同王五一样,铃铛就像信号,内核将数据处理好之后,就使用信号SIGIO通知应用程序,这种IO模型实际上也是非阻塞IO模型:

第四种,IO多路转接,它实际上是阻塞IO的plus版本,也就是说张三一个人进行阻塞IO的时候,赵六已经创建了100个张三的分身了,所以实际上的流程图也就是IO的流程图,那么多路转接也是我们后面的主题,介绍select poll epoll就是从这里引出的:

第五种,异步IO,异步IO实际上就是先让内核吧数据报准备好,再进行拷贝的,最后OS给应用程序发信号通知准备好了,这个过程田七只是作为发起IO,但是等的过程交给了内核,然后他再来负责拷贝,那么被称为异步IO就是因为发出 I/O 请求的线程不会阻塞等待,后续的 I/O 完成由内核负责异步处理,应用程序通过信号、回调或轮询某种状态(如 aio_error())来获取 I/O 是否完成,所以它是异步的。

那么以上五种IO中,第四种IO多路复用的效率是最高的,因为大大减少了等待了时间,这也是之后我们为什么围绕它展开的理由。


非阻塞IO

对于阻塞IO来说,是我们最常见,也是最经常使用的IO模型,但是如果我们今天想尝试一下非阻塞IO怎么办呢?我们可以使用函数fcntl

第一个参数是对应的文件描述符,第二个参数是执行的控制命令,第三个参数取决于第三个参数,可以忽略。

一般常用的cmd有F_SETFL,F_GETFL,GET用来获取状态标志,SET用来获取标志,比如我们想要将一个文件描述符设置为非阻塞的就可以这样操作:

void SetNoBlock()
{int n = ::fcntl(0, F_GETFL);if(n < 0)std::cout << "Error" << std::endl;else   fcntl(0, F_SETFL, n | O_NONBLOCK);
}int main() 
{SetNoBlock();while(true){char buffer[1024];ssize_t n = ::read(0, buffer, sizeof(buffer));if(n > 0){std::string str = buffer;std::cout << str << std::endl;}else if(n == 0){std::cout << "read done!" << std::endl;break;}else{// errno == 11 EWOULDBLOCK EAGAINif(errno == EWOULDBLOCK){continue;}std::cout << "GG" << std::endl;sleep(1);}}return 0;
}

我们会发现如果我们强行让read这种阻塞IO变成非阻塞IO,就会导致返回的值是负数,所以这个时候就有这种情况:发生错误是因为read本身出错还是因为非阻塞下没有数据可读导致read不会阻塞直接返回-1?所以我们可使用EWOULDBLOCK比较一下,当然了,它的本质是11,也是EAGAIN:

那么IO模型先到这里,算是一个开胃小菜~


感谢阅读!

http://www.xdnf.cn/news/566623.html

相关文章:

  • Flink基本理解
  • 初识Linux · NAT 内网穿透 内网打洞 代理
  • 【题解-洛谷】B4240 [海淀区小学组 2025] 最短字符串
  • buunctf Crypto-[NCTF2019]Keyboard1
  • 腾讯游戏安全与高通合作构建PC端游安全新格局
  • 改写视频生产流程!快手SketchVideo开源:通过线稿精准控制动态分镜的AI视频生成方案
  • Java开发-如何将一个字符串转换成一个数组,又如何把他转换成一个集合
  • Linux中I/O复用机制epoll
  • 【Netty】- 入门2
  • dify基于文本模型实现微调Fine-tune语料构造工作流
  • 在 Ubuntu 下通过 C APP程序实现串口发送数据并接收返回数据
  • OSCP备战-Stapler靶场详细步骤
  • 用java实现内网通讯,可多开客户端链接同一个服务器
  • 离线服务器算法部署环境配置
  • 深度解析 Element Plus
  • Flink CDC 3.4 发布, 优化高频 DDL 处理,支持 Batch 模式,新增 Iceberg 支持
  • naive-ui切换主题
  • 基于RT-Thread的STM32F4开发第六讲——PWM输出(CH1和CH1N)
  • DevOps学习回顾03-ops三部曲之配置管理(CM)
  • C++核心编程_初始化列表
  • Unity3D序列化机制详解
  • 云计算与大数据进阶 | 28、存储系统如何突破容量天花板?可扩展架构的核心技术与实践—— 分布式、弹性扩展、高可用的底层逻辑(下)
  • 游戏盾功能与技术解析
  • 电力设备制造企业数字化转型路径研究:从生产优化到生态重构
  • SpringBoot3+Vue3(2)-前端基本页面配置-登录界面编写-Axios请求封装-后端跨越请求错误
  • 【Java高阶面经:微服务篇】4.大促生存法则:微服务降级实战与高可用架构设计
  • 使用计算机视觉实现目标分类和计数!!超详细入门教程
  • uni-app(2):页面
  • 用python实现汉字转拼音工具
  • 【AI News | 20250521】每日AI进展