news 2026/5/13 18:13:56

五种IO模型

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
五种IO模型
  • 五种IO模型
  • 同步通信vs异步通信
  • 非阻塞IO

我们在进行IO的时候,分为两个过程等待资源就绪+拷贝。
因此IO=等+拷贝。
那么所谓的高效IO,就是降低等的占比

五种IO模型

我先以生活中钓鱼的例子来形容五种IO模型。
来钓鱼的人会有各种不同的行为。
首先是我们的张三,这是个非常专注的钓鱼者,他会全神贯注盯着鱼竿,期间不做任何事。
随之而来的是李四,李四则是在钓鱼的时候刷刷视频,时不时看看鱼竿有没有动静。
王五钓鱼又不同于他们,他将一个铃铛系在鱼竿上,然后就专心干自己的事情不去理会鱼竿,只有铃铛响了他才会去收杆。
赵六则是方圆十里的首富,他带来一百根鱼竿一起钓鱼,不断来回跑看看哪根鱼竿上钓了。
最后是田七,田七则不享受钓鱼的过程,只想要鱼,因此他不参与钓鱼的过程,让自己的手下去钓鱼。

我们将上述钓鱼过程中的人看成系统调用,鱼竿就是socket,湖是系统内部,🐟相当于数据,鱼漂浮动就是数据就绪,钓就是发生拷贝。

那么上述五种钓鱼行为对应五种钓鱼模型。
张三:阻塞IO
李四:非阻塞IO
王五:信号驱动IO
赵六:多路复用/多路转接IO
田七:异步IO

事实上,阻塞IO才是最常见的IO,占90%以上。因为他十分简单。所有的套接字,默认都是阻塞方式。
上述IO效率最高的自然就是多路复用IO。

同步通信vs异步通信

同步通信synchronouscommunication
异步通信asynchronous communication

我们将上述五种IO模型中的前四种称为同步IO,最后一种称为异步IO。
这时候就有人提出异议了:“诶,前面信号部分不是说过信号是异步的吗,那为什么信号驱动IO不是异步的?”
这里就要明确一下,这两个异步和同步不是一个概念。

通信中的同步和异步关注的是消息通信机制:

  • 所谓同步,就是在发出一个调用时,在没有得到结果之前,该调用就不返回.但是一旦调用返回,就得到返回值了;换句话说,就是由调用者主动等待这个调用的结果;
  • 异步则是相反,调用在发出之后,这个调用就直接返回了,所以没有返回结果; 换句话说,当一个异步过程调用发出后,调用者不会立刻得到结果;而是在调用发出后,被调用者通过状态、通知来通知调用者,或通过回调函数处理这个调用.

而我们进程、线程中的同步讲的是两种执行流的执行呈现一定顺序性。

非阻塞IO

我们这里浅浅讲一下非阻塞IO怎么实现。
我们正常打开open打开文件是阻塞方法打开的。注意到我们的open其实是可以传三个参数的:


我们传入O_NONBLOCK 或 O_NDELAY就能以非阻塞方式打开文件。

但是这样有违我们正常的编写习惯,这里还有个能将阻塞方法打开的文件描述符改为非阻塞的替代方案:

fcntl 函数有5种功能:
• 复制一个现有的描述符(cmd=F_DUPFD).
• 获得/设置文件描述符标记(cmd=F_GETFD或F_SETFD).
• 获得/设置文件状态标记(cmd=F_GETFL或F_SETFL).
• 获得/设置异步I/O所有权(cmd=F_GETOWN或F_SETOWN).
• 获得/设置记录锁(cmd=F_GETLK,F_SETLK或F_SETLKW).

我们此处只是用第三种功能,获取/设置文件状态标记,就可以将一个文件描述符设置为非阻塞.

如此我们就能实现一个将文件描述符设置为非阻塞的函数:

然后我们再编写一下主函数非阻塞轮询逻辑,还记得这个在我们进程等待的时候也用过非阻塞轮询的方法。
再次之前我们要知道read如果在非阻塞轮询时,没有读到数据会返回什么:

是的,读到数据就会出错返回。
那怎么区分真的出错还是没读到数据呢?
我们可以根据他设置的错误码不同,如果是没读到数据设置的错误码是:

EAGAIN 或EWOULDBLOCK。其实这两是一个值:


除此之外,read还有可能因为信号中断,这时错误码会设置为:

那么对这些特殊情况稍微处理一下之后:

intmain(){charbuffer[1024];SetNonBlock(0);while(true){printf("Enter# ");fflush(stdout);ssize_t n=::read(0,buffer,sizeof(buffer)-1);if(n>0){buffer[n]=0;printf("echo# %s",buffer);}elseif(n==0)// ctrl + d{printf("read done\n");break;}else{if(errno==EWOULDBLOCK){sleep(1);std::cout<<"底层数据没有就绪,开始轮询检测"<<std::endl;std::cout<<"可以做其他事情"<<std::endl;continue;}elseif(errno==EINTR){continue;}else{perror("read");break;}}}return0;}

尝试运行:

非常完美!

但是非阻塞IO往往需要程序员循环的方式反复尝试读写文件描述符,这个过程称为轮询.这对CPU来说是较大的浪费,一般只有特定场景下才使用.

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/5/10 15:34:29

RK3588中aarch64浮点运算单元启用操作指南

RK3588上如何真正“激活”aarch64的浮点算力&#xff1f;从寄存器到代码的实战解析你有没有遇到过这种情况&#xff1a;在RK3588开发板上跑一个图像滤波或AI推理程序&#xff0c;CPU占用率飙到90%以上&#xff0c;帧率却卡得像幻灯片&#xff1f;你以为是算法太重、模型太大&am…

作者头像 李华
网站建设 2026/5/12 1:44:42

直播停留超1小时的秘密:声网连麦打造沉浸式购物感

年终大促前&#xff0c;团队因后台流量数据陷入沉默&#xff1a;投放预算增加&#xff0c;直播间却留不住人&#xff0c;主播卖力叫卖&#xff0c;评论区冷清。同行低价竞争致用户审美疲劳&#xff0c;团队焦虑不已。我意识到叫卖行不通&#xff0c;用户需真实互动&#xff0c;…

作者头像 李华
网站建设 2026/5/12 17:29:08

STM32驱动2.8寸LCD全攻略

目录 一、引言 二、2.8 寸 LCD 硬件接口和工作原理 2.1 硬件接口 2.2 工作原理 三、LCD 驱动程序设计 3.1 初始化 3.2 数据传输 3.3 显示控制 四、基本图形显示程序模块 4.1 画点 4.2 画线 4.3 画矩形 4.4 画圆 4.5 显示字符 4.6 显示字符串 4.7 显示位图 五、…

作者头像 李华
网站建设 2026/5/13 9:56:20

Conda优先级配置解决清华镜像与其他channel冲突

Conda优先级配置解决清华镜像与其他channel冲突 在深度学习项目的实际开发中&#xff0c;一个看似微小的环境配置问题&#xff0c;往往能导致数小时甚至数天的调试浪费。你是否曾遇到过这样的场景&#xff1a;明明安装了 PyTorch 和 CUDA&#xff0c;torch.cuda.is_available()…

作者头像 李华
网站建设 2026/5/6 16:21:53

XPG网络验证

链接&#xff1a;https://pan.quark.cn/s/57cca3d7c1ea本验证端由炫语言编写 64位版本 采用sqlite3轻量本地数据库 加解密算法都是自写的因为不会逆向可能安全度不是很高 所以大家在接入软件后 还是用vmp加一下壳

作者头像 李华
网站建设 2026/5/10 12:06:04

多模态交互:语音、文本、图像的综合处理

多模态交互:语音、文本、图像的综合处理 关键词:多模态交互、语音处理、文本处理、图像处理、综合处理 摘要:本文聚焦于多模态交互中语音、文本、图像的综合处理技术。首先介绍了多模态交互的背景,包括目的、预期读者、文档结构和相关术语。接着阐述了语音、文本、图像的核…

作者头像 李华