【Linux】I/O多路复用

文章目录

  • I/O多路复用
    • select()
      • select()缺点
    • poll()
      • poll()缺点
    • epoll()
      • LT(水平触发模式)
      • ET(边缘触发模式)
      • 具体函数

I/O多路复用

  • 多进程和多线程实现并发会消耗大量的资源,主进程/线程用于监听和接受连接,再创建多个子进程/子线程来完成与连接的各个客户端的通信。
  • I/O多路复用使程序能够同时监听多个文件描述符,能够提高程序的性能,Linux下实现I/O多路复用的系统调用主要有select、poll、epoll。
  • 监听文件描述符的I/O请求实际上是检测其相应的I/O缓冲区是否有数据

select()

  • 构造一个文件描述符列表,限制1024个,将指定的需要被监听的文件描述符添加到该列表中,采用位视图法。
  • 调用一个系统函数监听列表中的文件描述符,直到这些描述符中的一个或者多个进行I/O操作时,该函数返回,该函数是阻塞的且由内核完成对文件描述符的检测操作,将用户态的文件描述符列表拷贝到内核态进行检测。
  • 返回时,会通知进程有几个文件描述符要进行I/O操作,将内核态检测的文件描述符列表更新再拷贝到用户态,具体是哪些文件描述符还需要从监听的文件描述符开始再次遍历更新后的文件描述符列表。
  • 因为内核会改变原本的文件描述符列表,所以需要设置两个列表,一个记录需要监听的文件描述符,仅在添加或删除文件描述符时改变,另一个负责送入内核进行检测并进行交互。
int select(int nfds, fd_set *readfds, fd_set *writefds, fd_set *exceptfds, struct timeval *timeout);
//成功时,返回准备好的文件描述符数量。被信号打断时,返回-1,超时时,返回0。//nfds: 需要监控的文件描述符集合中最大的文件描述符加1,即监控多少个文件描述符。//readfds: 指向一个fd_set文件描述符列表结构的指针,用于存放需要检查可读性的文件描述符集合,由内核完成对文件描述符的检测操作。//writefds: 同上,但用于存放需要检查可写性的文件描述符集合。//exceptfds: 同上,用于存放需要检查异常事件(如错误状态)的文件描述符集合。//timeout: 指定select调用的最长等待时间。如果为NULL,select将一直阻塞直到有描述符准备好;如果指向一个非零超时时间,则等待指定的时间,到期后无论是否有描述符准备好都将返回。fd_set read;//创建文件描述符列表,判断读
FD_ZERO(&read);//初始化列表
FD_SET(3,&read);//将文件描述符3添加到列表中
FD_SET(5,&read);//将文件描述符5添加到列表中
FD_SET(100,&read);//将文件描述符100添加到列表中
select(101,&read,NULL,NULL,NULL);//送入内核检测文件描述符的IO操作,并返回个数
FD_ISSET(3,&read);//判断文件描述符3是否在列表中
FD_CLR(100,&read);//将文件描述符100从列表中清除

select()缺点

  • 每次调用select都需要将文件描述符列表从用户态复制到内核态,开销较大
  • 在内核中每次都要遍历这个文件描述符列表,开销较大
  • select的文件描述符列表大小仅有1024个,个数较少
  • 文件描述符列表每次都要重置,需要两个文件描述符列表,一个用于记录需要监听的,另一个则和内核交互。

poll()

  • 使用pollfd结构体数组来记录需要监听的文件描述符和相应的事件,改进了select限制1024个文件描述符的大小,可以自行指定。
  • 结构体中还有events以及revents表示监听的事件和返回时触发的事件,不需要像select一样重置文件描述符列表。
  • 结构体数组需要拷贝到内核中,由内核对需要进行I/O操作的文件描述符进行检测
  • 返回时,会通知进程有几个文件描述符要进行I/O操作,具体是哪些文件描述符还需要遍历数组。
struct pollfd {int fd; /* 文件描述符 */short events;/* 监视的事件,可以是 POLLIN(读)、POLLOUT(写)、POLLERR(错误)等 */short revents;/* 返回时,被触发的事件 */
};
#include <poll.h>int poll(struct pollfd *fds, nfds_t nfds, int timeout);
//fds: 指向pollfd结构体数组的指针,每个结构体代表一个要监控的文件描述符及其相关的事件。//nfds: 数组fds中元素的个数,即要监控的文件描述符的数量。//timeout: 指定poll()函数的等待时间,单位为毫秒。可以是正值(等待指定的毫秒数后返回)、0(立即返回,不管文件描述符是否就绪)、-1(无限等待,直到至少有一个文件描述符就绪)

poll()缺点

  • 在处理文件描述符时,仍需要将结构体数组拷贝到内核且仍需遍历整个pollfd数组。
  • 返回值依然是需要执行I/O操作的文件描述符的个数,还需要遍历具体是哪些文件描述符。
  • 与select()一样,当监控的文件描述符数量巨大时,poll()需要维护一个较大的数组,这会消耗较多的内存

epoll()

  • epoll与poll大致相同但是epoll更为高效,采用红黑树作为底层的数据结构,通过epoll对象来监听处理多个文件描述符,epoll不仅会返回需要进行IO的文件描述符个数,也会直接返回具体的需要进行I/O的文件描述符,存储在epoll_event结构体数组中。
  • 创建对象后,内核维护的eventpoll结构体存储与epoll对象相关的信息,包括但不限于:
    一个红黑树(rb_root),用于快速插入和删除文件描述符(通过文件描述符的值作为键)。
    一个双向链表(rdlist),用于维护就绪事件epoll_event的列表,以供epoll_wait快速检索。
    一个等待队列头(wq),用于存放等待epoll_wait调用的进程。
  • epoll_event结构体
struct epoll_event {uint32_t events;   // 指定的和发生的事件掩码epoll_data_t data; // 用户定义的数据,可以存储文件描述符或其他信息
};//events字段可以是如下标志的组合:
/*
EPOLLIN:可读事件。
EPOLLOUT:可写事件。
EPOLLERR:错误事件。
EPOLLHUP:挂起事件。
EPOLLET(边缘触发)和EPOLLLEVEL(水平触发)等。
*/

LT(水平触发模式)

  • 在这种模式下,只要文件描述符上的事件(如可读、可写)保持激活状态,每次调用epoll_wait时,都会报告该事件。
  • 即使应用程序未完全处理完缓冲区中的数据,下次调用epoll_wait时,只要数据仍然可读(或可写),事件还会被触发。
  • 可能导致同一事件被多次报告,因此,应用程序需要能够处理重复的事件通知。

ET(边缘触发模式)

  • 在这种模式下,epoll_wait仅在文件描述符的就绪状态发生变化时报告一次事件,之后不会重复报告,除非该事件状态再次改变。
  • 一旦某个事件被消费(比如读取了新到的数据),直到又有新的数据到达或状态再次改变之前,epoll_wait不会再报告相同的事件。
  • 需要应用程序一次性完全处理事件,否则可能会错过后续的通知。例如,如果缓冲区中有数据可读但应用程序没有读完,下次调用epoll_wait可能不会再次通知,直到有新的数据到来。
  • 需要使用非阻塞的接口避免把处理多个文件描述符的任务饿死。
fcntl(fd, F_SETFL, fcntl(fd,F_GETFL,0)| O_NONBLOCK)//获取并设置非阻塞
  • 更节省资源,减少不必要的唤醒和上下文切换,适合处理高负载和高吞吐量的场景。

具体函数

int epoll = epoll_create(1); // 创建epoll对象,参数通常设为1,成功时返回新的epoll文件描述符,同时内核会生成一个eventpoll结构体用来负责维护一个高效的事件等待列表,以及处理文件描述符的添加、修改、删除和事件的等待与通知,epoll文件描述符用来标识该eventpoll结构体。struct epoll_event event;
event.events = EPOLLIN | EPOLLET; // 监听读事件,使用边缘触发模式event.data.fd = socket_fd; // 监听的socket描述符int epoll_ctl(int epfd, int op, int fd, struct epoll_event *event);
//控制epoll对象上的文件描述符监控事件,可以添加、修改或删除监控。
//成功时返回0,失败时返回-1并设置errno。
//epfd:由epoll_create返回的epoll文件描述符,标识eventpoll。
//op:操作类型,可以是
/*
EPOLL_CTL_ADD(添加)、EPOLL_CTL_MOD(修改)、EPOLL_CTL_DEL(删除)。
*/
//fd:要操作的文件描述符。
//event:指向epoll_event结构体的指针,指定了要监控的事件类型。int epoll_wait(int epfd, struct epoll_event *events, int maxevents, int timeout);
//等待一个或多个epoll事件的发生,获取准备就绪的epoll_enent事件。
//成功时返回就绪的文件描述符数量,0表示超时,-1表示出错。
//epfd:epoll文件描述符。
//events:指向epoll_event结构体数组的指针,用于存放发生的事件信息。
//maxevents:events数组的最大容量,即最多可以返回的事件数量。
//timeout:等待超时时间,单位为毫秒,-1表示无限等待,0表示立即返回,正值为等待的最长时间。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/diannao/28327.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

采煤vr事故灾害应急模拟救援训练降低生命财产损失

在化工工地&#xff0c;设备繁多、环境复杂&#xff0c;潜藏着众多安全隐患&#xff0c;稍有不慎便可能引发安全事故。为了保障工地的安全&#xff0c;我们急需一套全面、高效的安全管理解决方案。web3d开发公司深圳华锐视点研发的工地安全3D模拟仿真隐患排查系统&#xff0c;正…

可以用来制作硬模空心耳机壳的胶粘剂有哪些种类?

可以用来制作硬模空心耳机壳的胶粘剂有哪些种类&#xff1f; 制作耳机壳的胶粘剂有很多种类&#xff0c;常见的有环氧树脂胶水、UV树脂胶、快干胶、热熔胶等。 这些胶粘剂都有不同的特点和适用场景&#xff0c;可以根据自己的需求选择合适的类型。 例如&#xff1a; 环氧树脂…

css3新增伪类有哪些?

在 CSS3 中引入了一些新的伪类&#xff0c;用于向选择器添加特定的状态或行为。以下是一些常见的 CSS3 新增的伪类&#xff1a; :nth-child() 和 :nth-of-type()&#xff1a;根据元素在其父元素中的位置选择元素。例如&#xff0c;:nth-child(odd) 选择所有奇数位置的子元素。 …

pdf转图片,pdf转图片在线转

pdf转图片的方法&#xff0c;对于许多人来说可能是一个稍显陌生的操作。然而&#xff0c;在日常生活和工作中&#xff0c;我们有时确实需要将pdf文件转换为图片格式&#xff0c;以便于在特定的场合或平台上进行分享、展示或编辑。以下&#xff0c;我们将详细介绍一个pdf转成图片…

用宝塔部署vue+springboot上线公网详细步骤

首先自己在腾讯云中按照教程安装好宝塔。这是宝塔面板&#xff0c;获取登录宝塔的网址和账号密码。 1.在navicat新建数据库 如果出现权限问题&#xff0c;可以在宝塔数据库面板phpMyAdmin中进行权限设置 navicat可以修改用户权限 2.在宝塔面板新建数据库 3.将前端打包的dist文件…

linux 部署瑞数6实战(维普,药监局)第一部分

声明 本文章中所有内容仅供学习交流使用&#xff0c;不用于其他任何目的&#xff0c;抓包内容、敏感网址、数据接口等均已做脱敏处理&#xff0c;严禁用于商业用途和非法用途&#xff0c;否则由此产生的一切后果均与作者无关&#xff01;wx 本文章未经许可禁止转载&…

【星海随笔】云解决方案学习日志篇(二) kafka、Zookeeper、Fielbeat

Elastic 中国社区官方博客 https://blog.csdn.net/ubuntutouch/category_9209092.html Kafka kafka的源代码是基于Scala语言编写的&#xff0c;运行在Java虚拟机&#xff08;即:JVM&#xff09;上。因此&#xff0c;在安装kafka之前需要先安装JDK Kafka 为什么依赖 Zookeepe…

52. QT插件开发--插件程序(带ui文件)的创建与编译

1. 说明 一般情况下,针对代码量比较小的QT程序不需要进行插件集成化开发,但是针对大型程序来说,代码结构比较复杂,使用插件开发的方式可以提高代码开发和维护效率,团队之间的分工合作也会更加的明确。所谓插件式开发,实际上就是把程序的一部分功能封装起来,编译成一个单…

一血c++

题目描述 每一个竞赛选手都无法拒绝拿一血 "一血"其实就是同学们在榜单上看到的深绿色的标记&#xff0c;代表着某道题目&#xff0c;他是第一个通过的。 叶苡朋老师是一名资深信奥选手&#xff0c;在大学多次获奖&#xff0c;也是一个资深抢一血爱好者&#xff0…

认识Redis 主从同步、事务和Memcached的区别

08- 什么是 Redis 主从同步&#xff1f; Redis 的主从同步(replication)机制&#xff0c;允许 Slave 从 Master 那里&#xff0c;通过网络传输拷贝到完整的数据备份&#xff0c;从而达到主从机制。 主数据库可以进行读写操作&#xff0c;当发生写操作的时候自动将数据同步到从…

AES加密、DES加密和RC4加密的区别

AES加密、DES加密和RC4加密在多个方面存在显著区别。以下是这些加密算法的详细对比&#xff1a; AES加密 算法原理&#xff1a; AES&#xff08;Advanced Encryption Standard&#xff09;采用对称密钥加密&#xff0c;利用分组密码的原理&#xff0c;将明文分成多个128位的组…

【C语言】解决C语言报错:Use of Uninitialized Variable

文章目录 简介什么是Use of Uninitialized VariableUse of Uninitialized Variable的常见原因如何检测和调试Use of Uninitialized Variable解决Use of Uninitialized Variable的最佳实践详细实例解析示例1&#xff1a;局部变量未初始化示例2&#xff1a;数组未初始化示例3&…

分布式物联网平台特点

随着物联网&#xff08;IoT&#xff09;技术的飞速发展&#xff0c;我们正步入一个万物互联的新时代。在这个时代&#xff0c;设备、数据和服务的无缝集成是实现智能化的关键。分布式物联网平台作为这一进程的核心&#xff0c;正在成为构建智能世界的基石。 一、分布式物联网平…

0403用代入法求解递归式-分治策略-算法导论第三版

文章目录 1.代入法求解递归式步骤1.1 求解步骤1.2 边界条件 2.做出好的猜测3.微妙的细节4.避免陷阱5.改变变量 结语 1.代入法求解递归式步骤 1.1 求解步骤 代入法求解递归式分两步&#xff1a; 猜测解的形式。用数学归纳法求出解中的常数&#xff0c;并证明解是正确的。 当…

C++ 47 之 函数调用运算符重载

#include <iostream> #include <string> using namespace std;class MyPrint{ public:// 重载小括号() 重载谁operator后就紧跟谁的符号void operator()(string txt){cout << txt << endl;} };class MyAdd{ public:int operator()(int a, int b){retur…

【Pandas驯化-04】Pandas中drop_duplicates、describe、翻转操作

【Pandas驯化-04】Pandas中drop_duplicates、describe、翻转操作 本次修炼方法请往下查看 &#x1f308; 欢迎莅临我的个人主页 &#x1f448;这里是我工作、学习、实践 IT领域、真诚分享 踩坑集合&#xff0c;智慧小天地&#xff01; &#x1f387; 相关内容文档获取 微信公…

基于深度学习的光流预测

基于深度学习的光流预测 光流&#xff08;Optical Flow&#xff09;是指图像序列中像素的运动&#xff0c;即在连续的帧之间每个像素的移动向量。光流预测是计算机视觉中的一个重要任务&#xff0c;广泛应用于运动检测、视频分析、机器人导航等领域。基于深度学习的方法近年来…

redis大key优化

1.什么是大key以及可能造成的异常 1.1 什么大key redis是key,val型存储结构&#xff0c;key允许的最大大小为512MB&#xff0c;空字符串也是有效的键。大key是指value很大(占用大内存)。 常见的大key&#xff0c;大致可以这么分(根据具体redis规格以及实际压测而定): (1)单个…

搭建Python虚拟环境(五):Pyenv

使用Pyenv搭建虚拟环境的详细指南 Pyenv 是一个Python版本管理工具&#xff0c;可以让你在同一台机器上安装和管理多个Python版本。对于Windows用户&#xff0c;可以使用pyenv-win&#xff0c;这是一个专为Windows平台设计的Pyenv版本。本文将详细介绍如何使用Pyenv&#xff0…

判断子字符串是否存在

java判断字符串是否包含特定内容&#xff0c;用到contains语句 语法格式是 str.contains(string) 其中 str是字符串 string是查询字符串 示例代码如下 public class Stringcontains {public static void main(String[] args) {String str"今天的菜谱有:蒸羊羔&…