分享好友 最新动态首页 最新动态分类 切换频道
Linux五种IO模型和三种多路复用技术大详解
2025-04-29 15:25

作者:symen

在Linux系统中,实际上所有的I/O设备都被抽象为文件这个概念,一切皆文件(Everything is File)。无论是磁盘、网络数据、终端,还是进程间通信工具(如:管道pipe)等都被抽象为文件的概念。 这种设计使得 I/O 操作可以通过统一的文件描述符(File Descriptor, FD)来管理。 在了解多路复用select、poll、epoll实现之前,我们先简单回忆复习以下两个概念。


阻塞式I/O模型:

图片

在阻塞式 I/O 模型中,在I/O操作的两个阶段均会阻塞线程:

非阻塞式I/O模型:

图片

在非阻塞式 I/O 模型中,当进程发起 I/O 系统调用(如 )时:

信号驱动IO:

图片

在信号驱动 I/O 模型中,进程发起一个 I/O 操作时,会向内核注册一个信号处理函数(如 ),然后立即返回,不会被阻塞。当内核数据就绪时,会向进程发送一个信号,进程在信号处理函数中调用 I/O 操作(如 )读取数据。

异步IO

图片

在异步 I/O 模型中,当进程发起一个 I/O 操作时,会立即返回,不会被阻塞,也不会立即返回结果。内核会负责完成整个 I/O 操作(包括数据准备和复制到用户空间),并在操作完成后通知进程。如果 I/O 操作成功,进程可以直接获取到数据。

IO复用模型

图片

大多数文件系统的默认IO操作都是缓存IO。在Linux的缓存IO机制中,操作系统会将IO的数据缓存在文件系统的页缓存(page cache)。也就是说,数据会先被拷贝到操作系统内核的缓冲区中,然后才会从操作系统内核的缓存区拷贝到应用程序的地址空间中。这种做法的缺点就是,需要在应用程序地址空间和内核进行多次拷贝,这些拷贝动作所带来的CPU以及内存开销是非常大的。 至于为什么不能直接让磁盘控制器把数据送到应用程序的地址空间中呢?最简单的一个原因就是应用程序不能直接操作底层硬件。 总的来说,IO分两阶段: 1)数据准备阶段 2)内核空间复制回用户进程缓冲区阶段。如下图:

图片

目前支持I/O多路复用的系统调用有select,pselect,poll,epoll。与多进程和多线程技术相比,I/O多路复用技术的最大优势是系统开销小,系统不必创建进程/线程,也不必维护这些进程/线程,从而大大减小了系统的开销。 I/O多路复用就是通过一种机制,一个进程可以监视多个描述符,一旦某个描述符就绪(一般是读就绪或者写就绪),能够通知程序进行相应的读写操作。但select,poll,epoll本质上都是同步I/O,因为他们都需要在读写事件就绪后自己负责进行读写,也就是说这个读写过程是阻塞的,而异步I/O则无需自己负责进行读写,异步I/O的实现会负责把数据从内核拷贝到用户空间。

select

函数返回值:

从上述的select函数声明可以看出,fd_set本质是一个数组,为了方便我们操作该数组,操作系统提供了以下函数:

select 函数监视的文件描述符分3类,分别是writefds、readfds、和exceptfds,当用户process调用select的时候,select会将需要监控的readfds集合拷贝到内核空间(假设监控的仅仅是socket可读),然后遍历自己监控的skb(SocketBuffer),挨个调用skb的poll逻辑以便检查该socket是否有可读事件,遍历完所有的skb后,如果没有任何一个socket可读,那么select会调用schedule_timeout进入schedule循环,使得process进入睡眠。如果在timeout时间内某个socket上有数据可读了,或者等待timeout了,则调用select的process会被唤醒,接下来select就是遍历监控的集合,挨个收集可读事件并返回给用户了,相应的伪码如下:

下面的动图能更直观的让我们了解select:

图片

通过上面的select逻辑过程分析,相信大家都意识到,select存在三个问题:

[1] 每次调用select,都需要把被监控的fds集合从用户态空间拷贝到内核态空间,高并发场景下这样的拷贝会使得消耗的资源是很大的。[2] 能监听端口的数量有限,单个进程所能打开的最大连接数由FD_SETSIZE宏定义,监听上限就等于fds_bits位数组中所有元素的二进制位总数,其大小是32个整数的大小(在32位的机器上,大小就是3232,同理64位机器上为3264),当然我们可以对宏FD_SETSIZE进行修改,然后重新编译内核,但是性能可能会受到影响,一般该数和系统内存关系很大,具体数目可以cat /proc/sys/fs/file-max察看。32位机默认1024个,64位默认2048。

图片

[3] 被监控的fds集合中,只要有一个有数据可读,整个socket集合就会被遍历一次调用sk的poll函数收集可读事件:由于当初的需求是朴素,仅仅关心是否有数据可读这样一个事件,当事件通知来的时候,由于数据的到来是异步的,我们不知道事件来的时候,有多少个被监控的socket有数据可读了,于是,只能挨个遍历每个socket来收集可读事件了。

poll

函数参数:

函数返回值:

下面是poll的函数原型,poll改变了fds集合的描述方式,使用了pollfd结构而不是select的fd_set结构,使得poll支持的fds集合限制远大于select的1024。poll虽然解决了fds集合大小1024的限制问题,从实现来看。很明显它并没优化大量描述符数组被整体复制于用户态和内核态的地址空间之间,以及个别描述符就绪触发整体描述符集合的遍历的低效问题。poll随着监控的socket集合的增加性能线性下降,使得poll也并不适合用于大并发场景。

epoll

在 Linux 网络编程中, 曾长期被用作事件触发的机制。然而,随着高并发场景的需求增加, 的性能瓶颈逐渐显现。为了解决这些问题,Linux 内核引入了 机制。相比于 , 的最大优势在于其性能不会随着监听的文件描述符(fd)数量的增加而显著下降。如前面我们所说,在内核中的select实现中,它是采用轮询来处理的,轮询的fd数目越多,自然耗时越多。并且,在linux/posix_types.h头文件有这样的声明:

#define __FD_SETSIZE 1024 ( 最多只能同时监听 1024 个 fd(由 定义)。虽然可以通过修改内核头文件并重新编译内核来扩大这一限制,但这并不能从根本上解决问题。) 而 使用基于事件回调的机制,而不是轮询。它只会关注活跃的 fd,因此性能不会随着 fd 数量的增加而显著下降。

epoll_create 函数

的源码实现:

其中eventpoll 这个结构体中的几个成员的含义如下:

函数

函数

如下图,可以帮助我们理解的更加丝滑(/手动狗头):

图片

epoll的边缘触发与水平触发

1. 水平触发(LT): 关注点是数据是否有无,只要读缓冲区不为空,写缓冲区不满,那么epoll_wait就会一直返回就绪,水平触发是epoll的默认工作方式。适合对事件处理逻辑要求不高的场景。

2. 边缘触发(ET): 关注点是数据的变化。只有当缓冲区状态发生变化时(例如从空变为非空,或从非空变为空), 才会返回就绪状态。这里的数据变化并不单纯指缓冲区从有数据变为没有数据,或者从没有数据变为有数据,还包括了数据变多或者变少。即当buffer长度有变化时,就会触发。 假设epoll被设置为了边缘触发,当客户端写入了100个字符,由于缓冲区从0变为了100,于是服务端epoll_wait触发一次就绪,服务端读取了2个字节后不再读取。这个时候再去调用epoll_wait会发现不会就绪,只有当客户端再次写入数据后,才会触发就绪。 这就导致如果使用ET模式,那就必须保证要「一次性把数据读取&写入完」,否则会导致数据长期无法读取/写入。适合高性能场景,可以减少事件通知的次数,提高效率。

为什么比select,poll更高效?

从上图可以看出,epoll使用红黑树管理文件描述符,红黑树插入和删除的都是时间复杂度 O(logN),不会随着文件描述符数量增加而改变。 select、poll采用数组或者链表的形式管理文件描述符,那么在遍历文件描述符时,时间复杂度会随着文件描述的增加而增加,我们从以下几点分析epoll的优势:

最新文章
我的世界青芷柠源神奇宝贝游戏手机版我的世界神奇宝贝手机版下载「我的世界青芷柠源神奇宝贝游戏手机版」
青芷柠源神奇宝贝手机版是一款新的建造题材的模拟游戏,新的美妙的决斗玩法开启副本的挑战赛的模式完成最终的精灵成长之路实现自己的美妙人生就在这里开启无尽的副本模式去选择战斗吧各种精彩就在这里完成吧。1、趣味的探索时空的玩法,无
硬核解析 | 五菱灵眸智驾
全民智驾,是2025年汽车行业绕不开的主旋律,每一家车企都必须给出自己的回应。4月7日,在技术进化日上,五菱正式构建“天·灵·神”技术体系,发布四大关键技术:神炼电池、灵犀动力、灵眸智驾、灵语座舱。简单分个类,就是两项电动技术(
柔韧并济,内外兼修!leader木兰冰箱508,就是冰箱界的花木兰!
哈喽,节后还在努力调整节奏的小泽突然闪现~前不久跟办公室的小伙伴聊到工作和带娃的关系,同事说很佩服我工作中雷厉风行,回到家还能把家人照顾的这么好,我说哪有,我只是跟千万职场妈妈一样,努力做到上司眼中的工作狂,宝宝眼中的超人
新茶饮加速分化:蜜雪冰城赚了两个霸王茶姬
截至目前,新茶饮行业的四家上市公司均已披露年报。“新茶饮第一股”和去年奶茶行业唯一成功上市的,并没有先发制人,业绩双双出现下滑。其中,奈雪的茶面临从自营到加盟的转型压力,业绩转盈为亏,一下亏了九个多亿。另一端,资本市场的后
大容量电池 华为Mate 8佳木斯售2999!大容量电池手机「大容量电池 华为Mate 8佳木斯售2999!」
(中关村在线佳木斯行情)华为 的配置颇为强劲,采用麒麟950 8核心64位处理器,1080P屏幕,搭载4000mAh电池和9V2A快充,运行基于Android 6.0的EMUI系统,并做了芯片级加密,性能得到了全面升级。目前这款华为 (NXT-AL10/3GB RAM/全网通)
浙江杭州哪个奥特莱斯好?百元消费券免费领,下沙奥莱等你来逛
在杭州,有一种购物哲学叫“价格不妥协”。想要用划算的价格买到心仪好物,就来杭州下沙奥特莱斯。从国际奢品到运动潮牌,从“支付宝免费领百元消费券”到叠加名品折扣大放价,下沙奥莱用超值体验告诉你:美好生活,就在“家门口”!1、百
10年后,那个辞职看世界的女教师,后悔了吗?
“世界那么大,我想去看看。”十年前,一封只有10个字的辞职信在互联网上广泛流传。近日,这封信的作者,河南省实验中学心理教师顾少强,向媒体讲述了她的近况,再次引发人们的关注和讨论。顾少强的辞职信被誉为“最具情怀”的辞职信,在网
圣地安列斯手机版圣安地列斯手机版「圣地安列斯手机版」
侠盗列车圣地安列斯是一款非常好玩的冒险类游戏,游戏中自由度非常高,玩家来到一个开放世界,可以在城市里自由探索,同时你也可以拥有各种武器,只需用手机控制屏幕操作角色即可,同时还需要完成一系列人物,并且还会有你想象不到的事情发
金价突然暴涨!热搜沸了
金价又涨疯了!今天,金价相关话题再次冲上热搜。4月16日,现货黄金再创历史新高。截至目前,纽约黄金已破3300美元/盎司大关,涨幅超2%。当日国内金饰价格持续跟涨,记者从官网查询到,今日周大福足金饰品标价1006元/克,前一日标价990元/
4.23世界读书日 | 传递爱与知识,“益”起捐本书吧!
1.香洲区图书馆地址:珠海市香洲区健民路868号香山文化艺术中心;联系电话:0756-22981012.南屏镇永济社区新时代文明实践站地址:珠海市南屏镇屏湾一路新南湾市场五楼;联系电话:0756- 86783893.拱北市民艺术中心地址:珠海市香洲区联安路
相关文章
推荐文章
发表评论
0评