news 2026/5/1 7:18:06

五种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/1 6:56:47

USB-Blaster驱动与工业控制系统兼容性分析

USB-Blaster驱动为何总在工控现场“罢工”&#xff1f;一文讲透兼容性难题与实战解法你有没有遇到过这样的场景&#xff1a;项目到了交付现场&#xff0c;FPGA板子已经上电&#xff0c;信号也都正常&#xff0c;可当你把USB-Blaster插进工控机的USB口时——设备管理器里赫然显示…

作者头像 李华
网站建设 2026/5/1 7:15:26

卷积神经网络反向传播过程PyTorch自动求导机制解析

卷积神经网络反向传播过程PyTorch自动求导机制解析 在深度学习的实际开发中&#xff0c;一个常见的场景是&#xff1a;研究者刚刚设计好一个新的卷积神经网络结构&#xff0c;正准备进行训练&#xff0c;却卡在了反向传播的实现上——复杂的梯度推导、手动计算每一层的偏导数、…

作者头像 李华
网站建设 2026/4/27 19:57:30

Git分支策略:为PyTorch大型项目设计开发协作模式

Git分支策略&#xff1a;为PyTorch大型项目设计开发协作模式 在深度学习项目的实际研发中&#xff0c;团队常面临一个看似简单却影响深远的问题&#xff1a;为什么同一个模型代码&#xff0c;在研究员A的机器上训练稳定、收敛良好&#xff0c;换到服务器或另一位同事的环境中却…

作者头像 李华
网站建设 2026/5/1 6:55:51

WSL2图形界面支持运行PyTorch可视化训练进度条

WSL2图形界面支持运行PyTorch可视化训练进度条 在深度学习开发中&#xff0c;一个常见的困扰是&#xff1a;明明代码写好了&#xff0c;却只能靠打印日志“盲训”模型。尤其是在 Windows 环境下做研究或项目迭代时&#xff0c;想看看 tqdm 的进度条、画个 loss 曲线&#xff0…

作者头像 李华
网站建设 2026/4/20 0:30:17

利用PyTorch-CUDA镜像批量生成AI技术文章标题

利用PyTorch-CUDA镜像批量生成AI技术文章标题 在内容创作日益自动化、智能化的今天&#xff0c;如何高效地产出高质量的技术文章标题&#xff0c;已成为许多AI平台、自媒体团队甚至科研机构关注的核心问题。手动构思不仅耗时费力&#xff0c;还容易陷入风格不统一、关键词覆盖不…

作者头像 李华
网站建设 2026/4/29 14:36:24

Markdown语法高亮显示PyTorch代码块样式优化建议

PyTorch 代码在 Markdown 中的优雅呈现&#xff1a;从环境到文档的全链路优化 在深度学习项目开发中&#xff0c;我们常常面临一个看似微小却影响深远的问题&#xff1a;如何让别人一眼看懂你的 PyTorch 代码&#xff1f;不是指模型结构是否巧妙&#xff0c;而是——当你把一段…

作者头像 李华