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

IO复用(多路转接)

IO复用(多路转接)

请添加图片描述
请添加图片描述

五种IO模型

  • 阻塞IO: 在内核将数据准备好之前, 系统调用会一直等待. 所有的套接字, 默认都是阻塞方式.
    请添加图片描述

  • 非阻塞IO: 非阻塞 IO: 如果内核还未将数据准备好, 系统调用仍然会直接返回, 并且返回EWOULDBLOCK 错误码.

    请添加图片描述

  • 信号驱动IO: 内核将数据准备好的时候, 使用 SIGIO 信号通知应用程序进行 IO操作
    请添加图片描述

  • 多路转接:: 虽然从流程图上看起来和阻塞 IO 类似. 实际上最核心在于 IO 多路转接能够同时等待多个文件描述符的就绪状态.

    请添加图片描述

  • 异步 IO: 由内核在数据拷贝完成时, 通知应用程序(而信号驱动是告诉应用程序何时可以开始拷贝数据).
    请添加图片描述

总结

IO的核心都是等待 + IO, 日常中等待的时间远大于IO, 所以如何处理等待的时间就是我们处理IO需要考虑的问题。

如何将文件描述符设置成为非阻塞

由于Linux下一切皆文件, 所以我们这里考虑的是文件 + 特殊文件 + 套接字等等,由于对于文件描述符来说, 在Linux操作系统中通过struct file维护文件的基本的信息。默认情况下, 所有的文件都是设置成阻塞的。

文件属性操作的函数调用

请添加图片描述
)

// 当然也可以设置成为宏
void setNoBlock(int fd)
{// 获取文件当前状态int fl = ::fcntl(fd,F_GETFL);if(fl < 0){perror("fcntl获取失败");return;}// 在原来的基础上将文件属性加上NO_BLOCKfcntl(fd,F_SETFL, fl | O_NONBLOCK); }

多路转接

本文主要还是讨论,如何使用多路转接的方式。那么我们如何更加直观的理解多路转接的思想呢?

场景:

如果我们使用TCP建立Web服务, 当我们的多个用户来到后, 会产生很多的通信套接字, 这个时候如果我们是同步处理的服务,我们有很多种思路:

  1. 多线程 : 每个线程维护一个通信套接字,当通信结束后, 线程被线程池回收。但是缺点也很明显, 通信套接字通过三次握手建立成功后, 不一定获取,可能导致出现大量的不活跃的连接,这个时候,就会显著的浪费线程的资源。
  2. IO复用 : Linux内核帮助实现了IO复用模型,包括poll epoll select,实现方式不同,但是思路都一样,帮助我们管理一群非阻塞文件描述符, 类似于养鱼,当我们的操作系统或不断地遍历判断每个文件描述符的状态,就和我们的养鱼人会不断检查鱼的情况,当某个文件描述符读写就绪后,也就是鱼长大了,就会通知用户层,可以处理了。

上面我们是通俗的介绍了多路复用的原理,但是Linux实现多路复用的接口也有三种select poll epoll

select

 #include <sys/select.h>int select(int nfds, fd_set *readfds, fd_set *writefds,fd_set *exceptfds, struct timeval *timeout);void FD_CLR(int fd, fd_set *set);
int  FD_ISSET(int fd, fd_set *set);
void FD_SET(int fd, fd_set *set);
void FD_ZERO(fd_set *set);
  • nfds : 是需要管理的文件描述符的个数 + 1

  • rdset,wrset,exset 分别对应于需要检测的可读文件描述符的集合,可写文件描述符的集 合及异常文件描述符的集合;

  • timeout : 表示select的等待时间

fd_set是位图的类型, 类似于C++里面的std::bitmap, 通过一个bit表示文件描述组的状态。 后面的四个函数都是帮助我们操作fd_set这种类型。

缺点明显:

  • 每次调用 select, 都需要手动设置 fd 集合, 从接口使用角度来说也非常不便. • 每次调用 select,都需要把 fd 集合从用户态拷贝到内核态,这个开销在 fd 很多时会很大

  • 同时每次调用 select 都需要在内核遍历传递进来的所有 fd,这个开销在 fd多时也很大

  • select 支持的文件描述符数量太小.

poll

struct pollfd {int   fd;         /* file descriptor */short events;     /* requested events */short revents;    /* returned events */
};int poll(struct pollfd *fds, nfds_t nfds, int timeout);

不同于 select 使用三个位图来表示三个 fdset 的方式,poll 使用一个 pollfd 的指针实现.

pollfd 结构包含了要监视的 event 和发生的 event,不再使用 select“参数-值”传
递的方式. 接口使用比 select 更方便. • poll 并没有最大数量限制 (但是数量过大后性能也是会下降)

poll 的缺点 :

poll 中监听的文件描述符数目增多时和select函数一样poll 返回后,需要轮询 pollfd 来获取就绪的描述符. • 每次调用 poll 都需要把大量的 pollfd 结构从用户态拷贝到内核中. 同时连接的大量客户端在一时刻可能只有很少的处于就绪状态, 因此随着监视
的描述符数量的增长, 其效率也会线性下降.

epoll

请添加图片描述

为了处理大量句柄而进行改进的poll
epoll很多时候叫做epoll模型, 提供了一组构建epoll模型的函数, 面相对象, 而不是和select和poll一样更多的是面向过程。

// 创建一个epoll模型
int epoll_create(int size)int epoll_ctl(int epfd, int op,int fd,struct epoll_event* event);

epoll_ctl提供操作epoll模型的各种参数

  • op : 操作类型

    • EPOLL_CTL_ADD : 注册新的fd
    • EPOLL_CTL_MOD : 修改fd的事件
    • EPOLL_CTL_DEL : 删除fd
  • struct epoll_event

    events的几个宏(我们主要关心读和写)

    • EPOLLIN
    • EPOLLOUT
epoll时间就绪

请添加图片描述

int epoll_wait(int epfd, struct epoll_event * events, int maxevents, int timeout);

基于epoll模型实现的reactor反应堆模式(推广,epoll的使用场景)

reactor反应堆模式

总结select poll epoll的优缺点

  • select : select适合简单的应用场景(当我们需要管理的文件描述符比较少的时候), select是一个简单的不错的选择, 但是select频繁的将数据从内核到用户之间频繁拷贝, 当涉及到的描述符多了之后, 就会显著降低效率

  • poll : poll在select的基础之上进行了改进, 只能说在设计上更加的方便的, 但是轮询和用户内核之间的拷贝问题没有得到根本的解决

  • epoll : epoll模型是基于红黑树和嵌入式链表的设计的高效数据结构模型, 通过设置回调函数以及红黑树存储的机制, 使得通知用户层和拷贝进入内核的开销都得到了显著的降低(避免很多无用的拷贝)

http://www.dtcms.com/a/292908.html

相关文章:

  • c语言学习(days08)
  • 对比学习 | 软标签损失计算
  • 安科瑞工商业光储充新能源电站ACCU-100M微电网协调控制器
  • MyBatis-Plus 分页实战
  • 目前主流的AI深度学习框架对Windows和Linux的支持哪个更好
  • 单细胞转录组学+空间转录组的整合及思路
  • 一个不起眼的问题,导致插件加载失败
  • python中 tqdm ,itertuples 是什么
  • 学习软件测试的第十九天
  • ​Eyeriss 架构中的访存行为解析(腾讯元宝)
  • Java学习----Redis集群
  • SHAP的升级版:可解释性框架Alibi的相关介绍(一)
  • L1与L2正则化:核心差异全解析
  • RabbitMQ03——面试题
  • DOM/事件高级
  • haprox七层代理
  • 医院如何实现节能降耗?
  • <另一种思维:语言模型如何展现人类的时间认知>读后总结
  • 【上市公司变量测量】Python+FactSet Revere全球供应链数据库,测度供应链断裂与重构变量——丁浩员等(2024)《经济研究》复现
  • Day28| 122.买卖股票的最佳时机 II、55. 跳跃游戏、45.跳跃游戏 II、1005.K次取反后最大化的数组和
  • Spring AI Alibaba + JManus:从架构原理到生产落地的全栈实践——一篇面向 Java 架构师的 20 分钟深度阅读
  • MSTP实验
  • 深入理解 Qt 中的 QImage 与 QPixmap:底层机制、差异、优化策略全解析
  • 集训Demo5
  • 代码检测SonarQube+Git安装和规范
  • 从FDTD仿真到光学神经网络:机器学习在光子器件设计中的前沿应用工坊
  • Matlab学习笔记:界面使用
  • 【数据结构初阶】--栈和队列(二)
  • CanOpen--SDO 数据帧分析
  • vscode不识别vsix结尾的插件怎么解决?