高级IO模型之kqueue和epoll
简介
任何一个程序都离不开IO,有些是很明显的IO,比如文件的读写,也有一些是不明显的IO,比如网络数据的传输等。那么这些IO都有那些模式呢?我们在使用中应该如何选择呢?高级的IO模型kqueue和epoll是怎么工作的呢?一起来看看吧。
block IO和nonblocking IO
大家先来了解一下IO模型中最简单的两个模型:阻塞IO和非阻塞IO。
比如我们有多个线程要从一个Socket server中读取数据,那么这个读取过程其实可以分成两个部分,第一部分是等待socket的数据准备完毕,第二部分是读取对应的数据进行业务处理。对于阻塞IO来说,它的工作流程是这样的:
- 一个线程等待socket通道数据准备完毕。
- 当数据准备完毕之后,线程进行程序处理。
- 其他线程等待第一个线程结束之后,继续上述流程。
为什么叫做阻塞IO呢?这是因为当一个线程正在执行的过程中,其他线程只能等待,也就是说这个IO被阻塞了。
什么叫做非阻塞IO呢?
还是上面的例子,如果在非阻塞IO中它的工作流程是这样的:
- 一个线程尝试读取socket的数据。
- 如果socket中数据没有准备好,那么立即返回。
- 线程继续尝试读取socket的数据。
- 如果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/
最通俗的解读,最深刻的干货,最简洁的教程,众多你不知道的小技巧等你来发现!
欢迎关注我的公众号:「程序那些事」,懂技术,更懂你!
高级IO模型之kqueue和epoll的更多相关文章
- IO模型与select,poll,epoll
五种:阻塞,非阻塞,IO复印,信号驱动,异步. select,poll,epoll select: 典型用32个32位的整数表示1024个描述符,并发的局限. poll:功能同上,但数据结构不一样(链 ...
- linux基础编程:IO模型:阻塞/非阻塞/IO复用 同步/异步 Select/Epoll/AIO(转载)
IO概念 Linux的内核将所有外部设备都可以看做一个文件来操作.那么我们对与外部设备的操作都可以看做对文件进行操作.我们对一个文件的读写,都通过调用内核提供的系统调用:内核给我们返回一个file ...
- IO模型之IO多路复用 异步IO select poll epoll 的用法
IO 模型之 多路复用 IO 多路复用IO IO multiplexing 这个词可能有点陌生,但是如果我说 select/epoll ,大概就都能明白了.有些地方也称这种IO方式为 事件驱动IO ( ...
- 关于epoll的IO模型是同步异步的一次纠结过程
这篇文章的结论就是epoll属于同步非阻塞模型,这个东西貌似目前还是有争议,在新的2.6内核之后,epoll应该属于异步io的范围了,golang的高并发特性就是底层封装了epoll模型的函数,但也有 ...
- (转)Linux下select, poll和epoll IO模型的详解
Linux下select, poll和epoll IO模型的详解 原文:http://blog.csdn.net/tianmohust/article/details/6677985 一).Epoll ...
- 五种网络IO模型以及多路复用IO中select/epoll对比
下面都是以网络读数据为例 [2阶段网络IO] 第一阶段:等待数据 wait for data 第二阶段:从内核复制数据到用户 copy data from kernel to user 下面是5种网络 ...
- Linux 网络编程的5种IO模型:多路复用(select/poll/epoll)
Linux 网络编程的5种IO模型:多路复用(select/poll/epoll) 背景 我们在上一讲 Linux 网络编程的5种IO模型:阻塞IO与非阻塞IO中,对于其中的 阻塞/非阻塞IO 进行了 ...
- 哪5种IO模型?什么是select/poll/epoll?同步异步阻塞非阻塞有啥区别?全在这讲明白了!
系统中有哪5种IO模型?什么是 select/poll/epoll?同步异步阻塞非阻塞有啥区别? 本文地址http://yangjianyong.cn/?p=84转载无需经过作者本人授权 先解开第一个 ...
- IO模型介绍 以及同步异步阻塞非阻塞的区别
阻塞:用户进程访问数据时,如果未完成IO,等待IO操作完成或者进行系统调用来判断IO是否完成非阻塞:用户进程访问数据时,会马上返回一个状态值,无论是否完成 同步:用户进程发起IO(就绪判断)后,轮 ...
随机推荐
- finally块
/* finally 块: finally块的 使用前提是必须要存在try块才能使用. finally块的代码在任何情况下都会执行的,除了jvm退出的情况. finally非常适合做资源释放的工作,这 ...
- GFS 分布式文件系统
GFS 分布式文件系统 1.GlusterFS概述 : GlusterFS简介 a) GlusterFS是一-个开源的分布式文件系统. 由存储服务器.客户端以及NFS/Samba存储网关(可选,根据 ...
- JAVA String介绍、常量池及String、StringBuilder和StringBuffer得区别. 以及8种基本类型的包装类和常量池得简单介绍
一.概述 String是代表字符串的类,本身是一个最终类,使用final修饰,不能被继承. 二.定义方式 方式一:直接赋值法 String str1 = "hello"; 方式 ...
- 【CF712E】Memory and Casinos(数学 期望 DP)
题目链接 大意 给出一个序列,当你在某个点时,有一个向右走的概率\(P_i\)(向左为\(1-P_i\)), 给出\(M\)个操作,操作有两类: 1 X Y Z:把\(P_X\)的值修改为\(\fra ...
- MySQL之视图篇
MySQL之视图篇 文章目录 MySQL之视图篇 1. 概述 1.1 为什么使用视图? 1.2 视图的理解 2. 创建视图 2.1 创建单表视图 2.2 针对于多表 2.3 基于视图创建视图 3. 查 ...
- 树莓派使用docker安装青龙面板和改面板端口号
配置环境 系统:Raspbian 11(64位) 设备:树莓派4B 系统默认没有防火墙,所以就不用在防火墙中开放端口. 一.安装docker(已安装省略) 1.安装 curl -fsSL https: ...
- html-拖拽释放(Drag and drop) API
前言 本文总结一下html5 新增的元素拖拽功能的使用. 正文 1.H5之前的拖拽功能实现方法 JS 拖 拖 拽 功 能 的 实 现首先是三个事件,分别是 mousedown,mousemove,mo ...
- #刷题记录--剑指 Offer 07. 重建二叉树
输入某二叉树的前序遍历和中序遍历的结果,请重建该二叉树.假设输入的前序遍历和中序遍历的结果中都不含重复的数字. 抓住一点,通过递归进行节点创建时,是按照 前序遍历数组 进行创建的. 根节点,根节点的左 ...
- PDF太大怎么办?缩小PDF的4种常用方法
PDF太大怎么变小?我们在平时学习或生活中经常需要上传或提交一些资料,现在网站都是默认需要提交PDF格式的电子文档,有时提交资料会提示超过系统大小,如何才能使PDF缩小呢? 一.在线压缩 首先搜索sp ...
- 【C#基础概念】Ineterface 接口的设计原则
接口设计方式 自顶向下 (如图所示),自底向上(发现类需要结构了就声明一个接口). 接口的作用 用来解耦.继承 接口的本质