网易首页 > 网易号 > 正文 申请入驻

高级IO模型之kqueue和epoll

0
分享至

简介

任何一个程序都离不开IO,有些是很明显的IO,比如文件的读写,也有一些是不明显的IO,比如网络数据的传输等。那么这些IO都有那些模式呢?我们在使用中应该如何选择呢?高级的IO模型kqueue和epoll是怎么工作的呢?一起来看看吧。

block IO和nonblocking IO

大家先来了解一下IO模型中最简单的两个模型:阻塞IO和非阻塞IO。

比如我们有多个线程要从一个Socket server中读取数据,那么这个读取过程其实可以分成两个部分,第一部分是等待socket的数据准备完毕,第二部分是读取对应的数据进行业务处理。对于阻塞IO来说,它的工作流程是这样的:

  1. 一个线程等待socket通道数据准备完毕。

  2. 当数据准备完毕之后,线程进行程序处理。

  3. 其他线程等待第一个线程结束之后,继续上述流程。

为什么叫做阻塞IO呢?这是因为当一个线程正在执行的过程中,其他线程只能等待,也就是说这个IO被阻塞了。

什么叫做非阻塞IO呢?

还是上面的例子,如果在非阻塞IO中它的工作流程是这样的:

  1. 一个线程尝试读取socket的数据。

  2. 如果socket中数据没有准备好,那么立即返回。

  3. 线程继续尝试读取socket的数据。

  4. 如果socket中的数据准备好了,那么这个线程继续执行后续的程序处理步骤。

为什么叫做非阻塞IO呢?这是因为线程如果查询到socket没有数据,就会立刻返回。并不会将这个socket的IO操作阻塞。

从上面的分析可以看到,虽然非阻塞IO不会阻塞Socket,但是因为它会一直轮询Socket,所以并不会释放Socket。

IO多路复用和select

IO多路复用有很多种模型,select是最为常见的一种。实时不管是netty还是JAVA的NIO使用的都是select模型。

select模型是怎么工作的呢?

事实上select模型和非阻塞IO有点相似,不同的是select模型中有一个单独的线程专门用来检查socket中的数据是否就绪。如果发现数据已经就绪,select可以通过之前注册的事件处理器,选择通知具体的某一个数据处理线程。

这样的好处是虽然select这个线程本身是阻塞的,但是其他用来真正处理数据的线程却是非阻塞的。并且一个select线程其实可以用来监控多个socket连接,从而提高了IO的处理效率,因此select模型被应用在多个场合中。

为了更加详细的了解select的原理,我们来看一下unix下的select方法:

int select(int nfds, fd_set *readfds, fd_set *writefds, fd_set *errorfds, struct timeval *timeout);

先来解释一下这几个参数的含义,我们知道unix系统中,一切的对象都是文件,所以这里的fd表示的就是file descriptor ,也就是文件描述符。

fds表示的是 file descriptor sets,也就是文件描述符集合。

nfds是一个整数值,表示的是文件描述符集合中最大值+1.

readfds是要检查的文件读取的描述符集合。

writefds是要检查的文件写入的描述符集合。

errorfds是要检查的文件异常描述符集合。

timeout是超时时间,表示的是等待选择完成的最大间隔。

其工作原理是轮询所有的file descriptors,然后找到要监控的那些文件描述符,

poll

poll和select类很类似,只是描述fd集合的方式不同. poll主要是用在POSIX系统中。

epoll

实时上,select和poll虽然都是多路复用IO,但是他们都有些缺点。而epoll和kqueue就是对他们的优化。

epoll是linux系统中的系统命令,可以将其看做是event poll。首次是在linux核心的2.5.44版本引入的。

主要用来监控多个file descriptors其中的IO是否ready。

对于传统的select和poll来说,因为需要不断的遍历所有的file descriptors,所以每一次的select的执行效率是O(n) ,但是对于epoll来说,这个时间可以提升到O(1)。

这是因为epoll会在具体的监控事件发生的时候触发通知,所以不需要使用像select这样的轮询,其效率会更高。

epoll 使用红黑树 (RB-tree) 数据结构来跟踪当前正在监视的所有文件描述符。

epoll有三个api函数:

int epoll_create1(int flags);

用来创建一个epoll对象,并且返回它的file descriptor。传入的flags可以用来控制epoll的表现。

int epoll_ctl(int epfd, int op, int fd, struct epoll_event *event);

这个方法用来对epoll进行控制,可以用来监控具体哪些file descriptor和哪些事件。

这里的op可以是ADD, MODIFY 或者 DELETE。

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

epoll_wait用来监听使用epoll_ctl方法注册的事件。

epoll提供了两种触发模式,分别是 edge-triggered 和 level-triggered。

如果一个使用epoll注册的pipe收到了数据,那么调用epoll_wait将会返回,表示存在要读取的数据。但是在level-triggered模式下,只要管道的缓冲区包含要读取的数据,对 epoll_wait的调用将立即返回。但是在level-triggered模式下,epoll_wait 只会在新数据写入管道后返回。

kqueue

kqueue和epoll一样,都是用来替换select和poll的。不同的是kqueue被用在FreeBSD,NetBSD, OpenBSD, DragonFly BSD, 和 macOS中。

kqueue 不仅能够处理文件描述符事件,还可以用于各种其他通知,例如文件修改监视、信号、异步 I/O 事件 (AIO)、子进程状态更改监视和支持纳秒级分辨率的计时器,此外kqueue提供了一种方式除了内核提供的事件之外,还可以使用用户定义的事件。

kqueue提供了两个API,第一个是构建kqueue:

int kqueue(void);

第二个是创建kevent:

int kevent(int kq, const struct kevent *changelist, int nchanges, struct kevent *eventlist, int nevents, const struct timespec *timeout);

kevent中的第一个参数是要注册的kqueue,changelist是要监视的事件列表,nchanges表示要监听事件的长度,eventlist是kevent返回的事件列表,nevents表示要返回事件列表的长度,最后一个参数是timeout。

除此之外,kqueue还有一个用来初始化kevent结构体的EV_SET宏:

EV_SET(&kev, ident, filter, flags, fflags, data, udata);
epoll和kqueue的优势

epoll和kqueue之所以比select和poll更加高级, 是因为他们充分利用操作系统底层的功能,对于操作系统来说,数据什么时候ready是肯定知道的,通过向操作系统注册对应的事件,可以避免select的轮询操作,提升操作效率。

要注意的是,epoll和kqueue需要底层操作系统的支持,在使用的时候一定要注意对应的native libraries支持。

本文已收录于 http://www.flydean.com/14-kqueue-epoll/

特别声明:以上内容(如有图片或视频亦包括在内)为自媒体平台“网易号”用户上传并发布,本平台仅提供信息存储服务。

Notice: The content above (including the pictures and videos if any) is uploaded and posted by a user of NetEase Hao, which is a social media platform and only provides information storage services.

相关推荐
热点推荐
法国登顶!世界杯最新赔率榜出炉,阿根廷力压葡萄牙,荷兰上榜

法国登顶!世界杯最新赔率榜出炉,阿根廷力压葡萄牙,荷兰上榜

祥谈体育
2026-06-23 21:11:17
严重违纪违法,山东2名干部被开除党籍和公职

严重违纪违法,山东2名干部被开除党籍和公职

齐鲁壹点
2026-06-23 16:51:12
央视暗访曝光!直播间27个“茶农”,20个是演员,月入千万全靠演

央视暗访曝光!直播间27个“茶农”,20个是演员,月入千万全靠演

寒士之言本尊
2026-06-22 17:30:26
ESPN记者:绿军错失字母哥后,多支球队已准备报价杰伦-布朗

ESPN记者:绿军错失字母哥后,多支球队已准备报价杰伦-布朗

懂球帝
2026-06-23 21:00:10
死刑犯临刑前三停五口喝水,总指挥:暂停行刑,这是19年前的暗号

死刑犯临刑前三停五口喝水,总指挥:暂停行刑,这是19年前的暗号

星宇共鸣
2026-05-18 13:21:51
经常买虾的留意了:遇到这四类虾直接走开,内行都懂其中猫腻

经常买虾的留意了:遇到这四类虾直接走开,内行都懂其中猫腻

欣欣吃货爱美食
2026-06-20 21:33:20
“再走几步,可能就是生离死别!”上海医生突然冲出诊室,拦下一位老人!极易漏诊,高危救活几率只有15%

“再走几步,可能就是生离死别!”上海医生突然冲出诊室,拦下一位老人!极易漏诊,高危救活几率只有15%

环球网资讯
2026-06-23 15:10:28
李楠:新赛季作为北京主教练,有信心再创首钢篮球的辉煌

李楠:新赛季作为北京主教练,有信心再创首钢篮球的辉煌

狼叔评论
2026-06-23 19:19:03
俄专家一针见血,中国若要对日本动手,中国只有两个选择!

俄专家一针见血,中国若要对日本动手,中国只有两个选择!

张硜卤说体育
2026-06-22 11:47:28
未来球王!2026世界杯10位怪物级新星!

未来球王!2026世界杯10位怪物级新星!

ChicMyGeek
2026-06-21 11:07:19
苏州一台企违规雇佣印度人后续!上万网友举报,目前该企已被处罚

苏州一台企违规雇佣印度人后续!上万网友举报,目前该企已被处罚

小徐讲八卦
2026-06-23 17:55:14
大放狠话!一国党党魁要求承认“台湾是独立国家”。澳官媒:疯了,华人:不能投票给她

大放狠话!一国党党魁要求承认“台湾是独立国家”。澳官媒:疯了,华人:不能投票给她

澳洲红领巾
2026-06-23 14:31:46
警报拉响!菲律宾全面反华,连开3枪逼中国认栽,中国绝不退让

警报拉响!菲律宾全面反华,连开3枪逼中国认栽,中国绝不退让

小小科普员
2026-06-23 17:28:57
订单已排到8月,720万辆小电驴杀向全球,日本人这次是真坐不住了

订单已排到8月,720万辆小电驴杀向全球,日本人这次是真坐不住了

混沌录
2026-06-21 21:18:17
中国脑梗发病率世界第一!医生苦劝:罪魁祸首已揪出,这4物少吃

中国脑梗发病率世界第一!医生苦劝:罪魁祸首已揪出,这4物少吃

医学科普汇
2026-06-17 18:55:13
罗永浩曾痛批iPhone设计属于二流 苹果新CEO调转方向:将设计视为第一优先级

罗永浩曾痛批iPhone设计属于二流 苹果新CEO调转方向:将设计视为第一优先级

快科技
2026-06-22 23:04:05
iOS 27 更新,国行 iPhone AI 功能彻底移除!

iOS 27 更新,国行 iPhone AI 功能彻底移除!

花果科技
2026-06-23 15:13:52
火箭计划大幅调整阵容!愿听取各类交易报价:只有阿门接近非卖品

火箭计划大幅调整阵容!愿听取各类交易报价:只有阿门接近非卖品

罗说NBA
2026-06-23 05:44:37
雄鹿出全新15人名单!名记透露希罗或再换队:特纳库兹马还在询价

雄鹿出全新15人名单!名记透露希罗或再换队:特纳库兹马还在询价

颜小白的篮球梦
2026-06-23 19:01:44
1957年,周总理和夏梦的罕见合影,注意看总理的眼神,有点不一般

1957年,周总理和夏梦的罕见合影,注意看总理的眼神,有点不一般

明月清风阁
2026-06-23 13:00:10
2026-06-23 21:55:00
flydean程序那些事
flydean程序那些事
最通俗的解读,最深刻的干货!
356文章数 438关注度
往期回顾 全部

科技要闻

48名中国开发者联名举报苹果

头条要闻

河南南阳曾47天查扣24辆冷链货车:拍卖350万上缴国库

头条要闻

河南南阳曾47天查扣24辆冷链货车:拍卖350万上缴国库

体育要闻

扬尼斯去了迈阿密:凯尔特人怎么办?

娱乐要闻

内娱95后顶流格局发生潜移默化的变化

财经要闻

屋顶光伏度苦夏

汽车要闻

施鹏泽:为什么奥迪E7X强调座舱气味安全?

态度原创

房产
手机
亲子
本地
旅游

房产要闻

洞察新局|预算不变 居住升级 2026广州置业成本观察

手机要闻

realme P4x 4G手机海外发布:8000mAh电池,6.8寸720P高刷屏

亲子要闻

其实孩子就是你生命中的菩萨

本地新闻

吃一次广东龙舟饭,才懂什么是豪华盛宴

旅游要闻

滇中小众古寺,三月三上山搓草绳,安宁独有的百年祈福老习俗!

无障碍浏览 进入关怀版