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

高级IO

IO

用户层read&&write:本质就是把用户层数据写到OS,也就是拷贝

IO的本质:等待+拷贝

五种IO模型

1、阻塞式IO

2、非阻塞式IO

3、信号驱动IO

4、多路复用(多路转接),后面详细介绍

5、异步IO

同步通信和异步通信

同步:当发出一个调用时,如果没有结果,那就一直等,知道有结果再返回,这种就是调用者主动等待这个调用结果

异步:发出调用后,调用者不会等待结果,而是被调用者通过状态来通知调用者,或者通过回调函数来处理这个调用

注意:

这里的同步和线程之间的同步不是一个概念

进程/线程的同步是进程/线程直接制约关系,线程之间对共享资源访问时的保护

阻塞和非阻塞

阻塞调用:在得到返回结果之前,线程会被挂起,只有得到返回结果之后才返回

非阻塞调用:在得到返回结果之前,线程不会被阻塞

非阻塞IO往往需要循环的方式反复尝试读写文件描述符,也就是轮询

多路转接

select函数

参数部分:
参数 nfds 是需要监视的最大的文件描述符值 +1
rdset,wrset,exset 分别对应于需要检测的可读文件描述符的集合,可写文件描述符的集 合及异常文件描 述符的集合;
参数timeout为结构timeval,用来设置select()的等待时间
1、timeout参数设置为NULL,select一直阻塞,直到有事件产生
2、设置为0,仅检查文件描述符集合的状态,直接返回,并不等待外部事件的发生
3、特定事件值,如果在特定时间没有事件产生,select直接超时返回

fd_set

这是一个 位图,让 用户和内核之间传递文件是否就绪的信息
所以位图注定需要大量的位图操作,所以下列函数就提供了更方便的函数操作

当输入时 ,用户告诉内核,关注输入的一个或多个fd上的读事件(写事件或者异常事件),如果事件就绪了,内核要返回给用户

当输出时,内核告诉用户,fd上关注的事件(读、写或异常)已经就绪了

select缺点

1、等待的文件描述符有上限

2、输入和输出型参数参数多,导致数据拷贝的频率很高

3、每次都需要对关心的fd事件进行重置

4、用户层管理关心的fd,每次都需要遍历,内核检查fd事件是否就绪也需要遍历

poll

参数部分
fds 是一个 poll 函数监听的结构列表 . 每一个元素中 , 包含了三部分内容 : 文件描述符 , 监听的事件集合 ,
回的事件集合 .
nfds 表示 fds 数组的长度 .
timeout 表示 poll 函数的超时时间 , 单位是毫秒 (ms).
// pollfd结构
struct pollfd {
 int fd; /* file descriptor */
 short events; /* requested events */
 short revents; /* returned events */
};

这里events表示要关心的事件(用户填写),revents表示已经发生的事(内核填写)

 poll优点

与select相比,解决了select关心文件描述符上限重置问题

因为每次select都需要重置事件,但是poll的结构体解决了这个问题,只需要在结构体中添加关心事件

poll缺点

因为poll也是需要遍历fd,当文件描述符多的时候效率依旧不高

epoll

epoll_create

1、作用:创建一个epoll句柄,返回的文件描述符来调用epoll其他接口函数

2、参数可以省略

3、当不使用之后,需要使用close来关闭

epoll_ctl 

epoll事件注册函数

 

结构体epoll_data中不能存储一个有效的fd之后,有存储一个有效的ptr

epoll_wait

返回已经就绪的fd和事件

epoll原理

当epoll_create之后, 内核会创建一个结构体eventpoll,这个结构体中有两个成员非常关键

第一个是红黑树,注册的fd和事件就存放在里面

第二个是一个双链表,epoll_wait返回就绪的事件存放在其中

每个添加到epoll的事件都有与设备(网卡)驱动的回调函数,当相应事件发生时,就会触发这个回调函数,函数会把就绪事件挂到双链表中

所以判断是否有事件就绪,就只需要判断双链表是否为空

epoll的优点

1、检查就绪O(1),获取就绪O(N)

2、fd和event没有上限

3、返回值n,就是就绪的事件个数

水平触发和边缘触发

LT(Level Triggered) 水平触发

epoll默认下就是LT,当有事件就绪时,可以不处理或者只处理一部分

比如当读了一部分数据,但是还有一部分在缓冲区,下次调用epoll_wait时,也会立刻通知事件就绪,直到缓冲区数据被读完,epoll_wait才不会立即返回事件就绪

支持阻塞读写和非阻塞读写

ET(Edge Triggered)边缘触发

事件就绪时,必须立即处理

与上述例子相同,如果缓冲区数据没有读完,下次epoll_wait就不会再返回了,事件就绪之后,只有一次处理机会

只支持非阻塞读写

select和poll在工作模式下是LT,epoll两种方法都支持

这里为什么ET不支持阻塞读写?

如下图,如果没有读完数据,那么就需要再把数据读出来,才会对客户端进行应答,但是这里的问题是ET模式下认为资源没有就绪,所以Server端就会等Client再发消息,但是Client一直在等Server端的应答

LT和ET对比

1、LT是默认行为,ET减少epoll触发次数,但是每次就绪就必须把数据处理完

2、ET的逻辑更为复杂

惊群效应

在多线程下epoll可能惊群效应,惊群效应产生原因?导致什么结果?

在多线程或者多进程条件下,为了提高程序稳定性,会让多个线程或者多个进程同时在epoll_wait监听socket的描述符。当接收到一个新链接请求时,操作系统不知道把这个新链接交给那个线程,所以就会把所有线程唤醒。

但是只有一个线程会来处理这个链接,那么其他的线程都会失败,并且把errno设置为EAGAIN,这种现象就是惊群效应

这种导致资源额外开销和性能的损失

解决办法

1、唤醒部分子进程,仍然只有一个子进程处理链接,其他失败捕获EAGAIN错误,并无视

2、保证永远只有一个子进程在监听socket上的epoll_wait,主要思路就是申请一个全局锁

      但是当链接数占链接总数大部分之后,就不再加锁,每个子进程专注处理已经连接好的事件请求


http://www.kler.cn/a/417311.html

相关文章:

  • 【慕伏白教程】Zerotier 连接与简单配置
  • maven如何分析指定jar包的依赖路径
  • H266/VVC 环路滤波中去块滤波 DF 技术
  • Fedora 的 2025 年展望:AI 集成与 HDR 支持打造强大 Linux 桌面体验
  • JS:将JS对象格式化为php语法形式(完美支持无unicode编码匹配的正则)
  • 【Day31 LeetCode】动态规划DP Ⅳ
  • Golang面经
  • Linux 安装scala
  • Ansible自动化一键部署单节点集群架构
  • zotero文献阅读配置1:待更新
  • 【Oracle11g SQL详解】ORDER BY 子句的排序规则与应用
  • pandas数据处理及其数据可视化的全流程
  • 爬虫与反爬-旋转验证码突破方案(知名短视频、TK海外版 及 某东等等)
  • Java设计模式 —— 【创建型模式】原型模式(浅拷贝、深拷贝)详解
  • (附项目源码)PHP开发语言,225 基于PHP的高校二手物品交易系统的设计与实现,计算机毕设程序开发+文案(LW+PPT)
  • 深入理解异步编程:使用 `asyncio` 和 `aiohttp` 进行并发请求
  • 性能测试工具Grafana、InfluxDB和Collectd的搭建
  • Linux - 时间服务器
  • springboot学习-spring-boot-data-jdbc分页/排序/多表查询的例子
  • 基于大数据python 房屋价格数据分析预测可视化系统(源码+LW+部署讲解+数据库+ppt)
  • ESP32-S3模组上跑通ES8388(10)
  • CommonJS 和 ES Modules 的 区别
  • uniapp配置全局消息提醒
  • Spring - RabbitMQ循环依赖问题解决
  • 【英特尔IA-32架构软件开发者开发手册第3卷:系统编程指南】2001年版翻译,2-39
  • QT开发准则