epoll简介(二)
一:多路复用的举例
以一个生活中的例子来解释:
假设你在大学中读书,要等待一个朋友(数据)来访(要读),而这个朋友只知道你在A号楼(socket集合),但是不知道你具体住在哪里,于是你们约好了在A号楼门口见面。
如果你使用的阻塞IO模型来处理这个问题,那么你就只能一直守候在A号楼门口等待朋友的到来,在这段时间里你不能做别的事情,不难知道,这种方式的效率是低下的。
现在时代变化了,开始使用多路复用IO模型来处理这个问题。你告诉你的朋友来了A号楼找楼管大妈,让她告诉你该怎么走。这里的楼管大妈扮演的就是多路复用IO的角色(select,poll,epoll)。
select版大妈做的是如下的事情:比如同学甲的朋友来了,select版大妈比较笨,她带着朋友挨个房间进行查询谁是同学甲,你等的朋友来了。在实际的代码中,select版大妈做的是以下的事情:
int n = select(&readset,NULL,NULL,100);
for (int i = 0; n > 0; ++i)
{
if (FD_ISSET(fdarray[i], &readset))
{
do_something(fdarray[i]);
--n;
}
}
epoll版大妈就比较先进了:她记下了同学甲的信息,比如说他的房间号(socket fd),那么等同学甲的朋友到来时,只需要告诉该朋友同学甲在哪个房间即可,不用自己亲自带着人满大楼的找人了。epoll版大妈做的事情可以用如下的代码表示:
n = epoll_wait(epfd,events,20,500);
for(i=0;i<n;++i)
{
do_something(events[n]);
}
在epoll中,关键的数据结构epoll_event定义如下:
typedef union epoll_data
{
void *ptr;
int fd;
__uint32_t u32;
__uint64_t u64;
} epoll_data_t; struct epoll_event
{
__uint32_t events; /* Epoll events */
epoll_data_t data; /* User data variable */
};
可以看到,epoll_data是一个union结构体,它就是epoll版大妈用于保存同学信息的结构体,它可以保存很多类型的信息:fd,指针等等。有了这个结构体,epoll大妈可以不用吹灰之力就可以定位到同学甲。
别小看了这些效率的提高,在一个大规模并发的服务器中,轮询IO是最耗时间的操作之一。再回到那个例子中,如果每到来一个朋友楼管大妈都要全楼的查询同学,那么处理的效率必然就低下了,过不久楼底就有不少的人了。
二:select和poll
尽管poll和select完成一样的工作,但是poll仍然优于select:
1:poll无需使用者计算最大的文件描述符值加一和传递该参数。
2:poll在应对较大值的文件描述符时更具效率。想象一下select监视值为900的文件描述符时的情况,内核需要检查每个集合中的每个比特位,直到第900个。
3:select的文件描述符集合是静态大小的,所以要做出权衡:要么集合很小,限制了select可以监视的文件描述符的最大值,要么很大,但是效率不高。尤其是当不能确定集合的组成是否稀疏时,对较大掩码的操作效率不高。而用poll则可以创建合适大小的数组。
4:若用select,文件描述符集合会在返回时重新创建,这样的话,之后每个调用都必须重新初始化它们。poll调用分离了输入(events)和输出(revents),数组无需改变即可重用。
select的参数类型fd_set没有将文件描述符和事件绑定,它仅仅是一个文件描述符集合。内核对fd_set集合的修改,使应用程序在下次调用select的时候,需要重置3个fd_set集合。
poll的参数pollfd要比select聪明一些,它把文件描述符和事件都定义在其中,内核每次修改的是pollfd结构体中的revents成员,而events成员保持不变,因此下次调用poll的时候,无需重置。
5:select的timeout参数在返回时是未定义的。
但是select系统调用也有几个不错的地方:
1:某些系统不支持poll,所以select的可移植性更好。
2:select提供了更好的超时方案:直到微妙级。
三:epoll
select和poll都只能工作在相对低效的LT模式,而epoll可以工作在ET模式,而且还支持EPOLLONESHOT事件,该事件可以进一步减少可读、可写和异常事件触发的次数。
从内核实现原理上来说,select和poll采用的都是轮询的方式,即每次调用都要扫描整个注册文件描述符集合,并将其中就绪的文件描述符返回给用户程序,因此它们检测就绪事件的时间复杂度是O(n)。
epoll_wait则不同,它采用的是回调的方式。内核检测到就绪的文件描述符时,将触发回调函数,回调函数就将该文件描述符上对应的事件插人内核就绪事件队列。内核最后在适当的时机将该就绪事件队列中的内容拷贝到用户空间。因此epoll_wait无须轮询整个文件描述符集合来检洲哪些事件已经就绪,其算法时问复杂度是0(1)。
但是。当活动连接比较多的时候。epoll_wait的效率未必比就select和poll高,因为此时回调函数被触发得过于频繁。所以epoll_wait适用于连接数量多,但活动连接较少的情况。
从应用程序的角度看,每次select和poll调用,都返回整个用户注册的事件集合,包括就绪的和未就绪的,所以应用程序寻找就绪文件描述符的时间是O(n)。
epoll采用完全不同的方式来管理用户注册的事件,它在内核中维护事件表,提供独立的系统调用epoll_ctl进行添加,删除,修改事件。这样,每次epoll_wait调用都直接从内核事件表中取得用户注册的事件,而无需反复从用户空间读入这些事件,而且,epoll_wait只返回就绪事件,所以,应用程序寻找就绪文件描述符的时间为O(1)。
四:其他
当我们执行epoll_ctl时,除了把socket放到epoll文件系统里file对象对应的红黑树上之外,还会给内核中断处理程序注册一个回调函数,告诉内核,如果这个描述符的中断到了,就把它放到准备就绪list链表里。所以,当一个socket上有数据到了,内核在把网卡上的数据copy到内核中后,然后把socket插入到准备就绪链表里。
如此,一颗红黑树,一张准备就绪句柄链表,少量的内核cache,就帮我们解决了大并发下的socket处理问题。执行epoll_create时,创建了红黑树和就绪链表,执行epoll_ctl时,如果增加socket,则检查在红黑树中是否存在,存在立即返回,不存在则添加到树干上,然后向内核注册回调函数,用于当中断事件来临时向准备就绪链表中插入数据。执行epoll_wait时立刻返回准备就绪链表里的数据即可。
epoll简介(二)的更多相关文章
- Epoll简介以及例子
第一部分:Epoll简介 问题 : Select,Poll和Epoll的区别 答案 : Epoll和Select的区别 1. 遍历方式的区别.select判断是否有事件发生是遍历的,而epoll是事 ...
- {Django基础七之Ajax} 一 Ajax简介 二 Ajax使用 三 Ajax请求设置csrf_token 四 关于json 五 补充一个SweetAlert插件(了解)
Django基础七之Ajax 本节目录 一 Ajax简介 二 Ajax使用 三 Ajax请求设置csrf_token 四 关于json 五 补充一个SweetAlert插件(了解) 一 Ajax简介 ...
- Windbg 脚本命令简介 二, Windbg command
Windbg 脚本命令简介 二, Windbg script command $<, $><, $$<, $$><, $$>a< (Run Scri ...
- epoll简介
1.epoll简介 epoll是I/O事件通知工具,与select/poll相比,epoll最大的好处在于它不会随着监听fd数目的增长而效率降低.epoll API既可以用作edge触发的接口,也可以 ...
- {Django基础七之Ajax} 一 Ajax简介 二 Ajax使用 三 Ajax请求设置csrf_token 四 关于json 五 补充一个SweetAlert插件(了解)
{Django基础七之Ajax} 一 Ajax简介 二 Ajax使用 三 Ajax请求设置csrf_token 四 关于json 五 补充一个SweetAlert插件(了解) Django基础七之 ...
- 基本I/O模型与Epoll简介
5种基本的I/O模型:1)阻塞I/O ;2)非阻塞I/O; 3)I/O复用(select和poll);4)信号驱动I/O(SIGIO);5)异步I/O(POSIX.1的aio_系列函数). 操作系统中 ...
- epoll简介 与 UDP server的实现
Abstractepoll是Linux内核为处理大批量句柄而作了改进的poll,是Linux下多路复用IO接口select/poll的增强版本,它能显著减少程序在大量并发连接中只有少量活跃的情况下的系 ...
- epoll简介(一)
一:概述 1:简介 EPOLL类似于POLL,是Linux特有的一种IO多路复用的机制.它在2.5.44内核中引入. 对于大量的描述符处理,EPOLL更有优势,它提供了三个系统调用来创建管理epo ...
- WPF Binding值转换器ValueConverter使用简介(二)-IMultiValueConverter
注: 需要继承IMultiValueConverter接口,接口使用和IValueConverter逻辑相同. 一.MultiBinding+Converter 多值绑定及多值转换实例 当纵向流量大于 ...
随机推荐
- Python缩进和选择
Python缩进和选择 缩进 Python最具特色的是用缩进来标明成块的代码.我下面以if选择结构来举例.if后面跟随条件,如果条件成立,则执行归属于if的一个代码块. 先看C语言的表达方式(注意,这 ...
- wpf样式与行为
- Ubuntu linux下部署golang配置环境,极客学院 无闻讲的安装配置是错的,折腾我好几遍,真是有点坑
开始按极客学院无闻讲的做,弄了几遍都不行,最后发现是错的,别人告诉我这是mac下的virtualbox是这样的,不管怎样,被坑的不浅. 虽然sudo apt install golang-go 就能安 ...
- birt运行环境
1.下载 http://pan.baidu.com/s/1nvhz5wt 2.解压birt-runtime-4.6.0-20160607.zip 将WebViewerExample更名为birt,复制 ...
- Linux巨好用的
受不了了windows下配置烦死人.linux一站式搞定,无敌 安装python3 机子上py2 py3共存没问题 安装virtualenv (py3)分割实验环境非常稳 安装mysql 先安装了一 ...
- 百分比宽度并排元素浮动之后,设置margin,padding换行的问题
今天遇到一个问题, 如下图,右边的div加了内边距换行: 解决方法: box-sizing: border-box;
- php 单向散列加密
1.加密文件 <?php //sha1_en.php header("content-type:text/html;charset=utf-8"); $str = " ...
- 消息队列rabbitmq rabbitMQ安装
消息队列rabbitmq 12.1 rabbitMQ 1. 你了解的消息队列 生活里的消息队列,如同邮局的邮箱, 如果没邮箱的话, 邮件必须找到邮件那个人,递给他,才玩完成,那这个任务会处理的很麻 ...
- Object Pool 对象池的C++11使用(转)
很多系统对资源的访问快捷性及可预测性有严格要求,列入包括网络连接.对象实例.线程和内存.而且还要求解决方案可扩展,能应付存在大量资源的情形. object pool针对特定类型的对象循环利用,这些对象 ...
- 国内首个全域边缘节点服务发布,阿里云助力企业把握5G机遇
7月24日,阿里云峰会开发者大会在上海世博中心举办.作为2019年首场最受瞩目的云计算开发者大会,阿里云携一众云计算技术大牛与开发者面对面,探讨各自领域的技术干货与前沿趋势.同时,也发布了多项重大重磅 ...