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 多值绑定及多值转换实例 当纵向流量大于 ...
随机推荐
- [jnhs]id字段修改错误导致hibernate hql查询整表只返回第一条数据
调试发现,查询到的就是一条数据 hql语句执行结果 Hibernate: select ballmodel0_.ball_id as ball_id1_1_, ballmodel0_.color as ...
- pycharm解决无法调用同文件夹下的文件
一.将所有的文件放在project这个根目录下面 二.添加一个空的__init__.py 文件 三.选中project根目录,点击右键选择make_directory as-->sources ...
- birt运行环境
1.下载 http://pan.baidu.com/s/1nvhz5wt 2.解压birt-runtime-4.6.0-20160607.zip 将WebViewerExample更名为birt,复制 ...
- 2019-4-16-C#-在-8.0-对比-string-和-string_-的类型
title author date CreateTime categories C# 在 8.0 对比 string 和 string? 的类型 lindexi 2019-04-16 10:16:56 ...
- ML面试1000题系列(81-90)
本文总结ML面试常见的问题集 转载来源:https://blog.csdn.net/v_july_v/article/details/78121924 81.已知一组数据的协方差矩阵P,下面关于主分量 ...
- Session学习小结
前言: 1.我们在学习一项技术的时候,首先应该是什么时候会用到这项技术.这次学习session也是如此,一般的web项目中都有用户的存在,有用户那么就有了用户的管理,而用户往往是存在于session中 ...
- 【JZOJ3623】【SDOI2014】数表(table) 树状数组+离线+莫比乌斯反演
题面 100 \[ Ans=\sum_{i=1}^n\sum_{j=1}^mg(gcd(i,j)) \] 其中, \[ g(d)=\sum_{i|d}i \] 我们注意到\(gcd(i,j)\)最多有 ...
- 蚁群算法MATLAB解TSP问题
Excel表exp12_3_1.xls中数据为: clc clear all [xdata,textdata]=xlsread('exp12_3_1.xls'); %加载20个城市的数据,数据按照表格 ...
- Python 字符编码处理总结
Python中经常遇到这样那样的字符编码问题,尤其在处理网页源码时(特别是爬虫中): UnicodeDecodeError: 'XXX' codec can't decode bytes in pos ...
- 2017年Android SDK下载安装及配置教程(附带原文地址)
首先声明: Unity版本5.6.3f1 最近试着在Unity中利用高通做AR开发时,发布项目文件需要发布到Android平台,遇到一些问题,看了网上的一些资料,踩了一些坑,现在总结出来,希望有相同的 ...