epoll
select poll epoll系统调用详细分析
epoll是Linux内核为处理大批量文件描述符而作了改进的poll,是Linux下多路复用IO接口select/poll的增强版本,它能显著提高程序在大量并发连接中只有少量活跃的情况下的系统CPU利用率。另一点原因就是获取事件的时候,它无须遍历整个被侦听的描述符集,只要遍历那些被内核IO事件异步唤醒而加入Ready队列的描述符集合就行了。epoll除了提供select/poll那种IO事件的水平触发(Level Triggered)外,还提供了边缘触发(Edge Triggered),这就使得用户空间程序有可能缓存IO状态,减少epoll_wait/epoll_pwait的调用,提高应用程序效率。
epoll的EPOLLLT模式和EPOLLET模式比较
http://blog.csdn.net/lcabcdefg/article/details/7243277
epoll是linux系统最新的处理多连接的高效率模型, 工作在两种方式下, EPOLLLT方式和EPOLLET方式。
EPOLLLT是系统默认, 工作在这种方式下, 程序员不易出问题, 在接收数据时,只要socket输入缓存有数据,
都能够获得EPOLLIN的持续通知, 同样在发送数据时, 只要发送缓存够用, 都会有持续不间断的EPOLLOUT
通知。而对于EPOLLET是另外一种触发方式, 比EPOLLLT要高效很多, 对程序员的要求也多些, 程序员必须
小心使用,因为工作在此种方式下时, 在接收数据时, 如果有数据只会通知一次, 假如read时未读完数据,
那么不会再有EPOLLIN的通知了, 直到下次有新的数据到达时为止; 当发送数据时, 如果发送缓存未满也只有
一次EPOLLOUT的通知, 除非你把发送缓存塞满了, 才会有第二次EPOLLOUT通知的机会, 所以在此方式下
read和write时都要处理好。 暂时写到这里, 留作备忘。
附加: 如果将一个socket描述符添加到两个epoll中, 那么即使在EPOLLET模式下, 只要前一个epoll_wait时,未读完, 那么后一个epoll_wait事件时, 也会得到读的通知, 但前一个读完的情况下, 后一个epoll就不会得到读事件的通知了。。。。。
epoll和select区别
http://blog.csdn.net/ysu108/article/details/7570571
区别(epoll相对select优点)主要有三:
1.select的句柄数目受限,在linux/posix_types.h头文件有这样的声明:#define __FD_SETSIZE 1024 表示select最多同时监听1024个fd。而epoll没有,它的限制是最大的打开文件句柄数目。
2.epoll的最大好处是不会随着FD的数目增长而降低效率,在selec中采用轮询处理,其中的数据结构类似一个数组的数据结构,而epoll 是维护一个队列,直接看队列是不是空就可以了。epoll只会对"活跃"的socket进行操作---这是因为在内核实现中epoll是根据每个fd上面 的callback函数实现的。那么,只有"活跃"的socket才会主动的去调用 callback函数(把这个句柄加入队列),其他idle状态句柄则不会,在这点上,epoll实现了一个"伪"AIO。但是如果绝大部分的I/O都是 “活跃的”,每个I/O端口使用率很高的话,epoll效率不一定比select高(可能是要维护队列复杂)。
3.使用mmap加速内核与用户空间的消息传递。无论是select,poll还是epoll都需要内核把FD消息通知给用户空间,如何避免不必要的内存拷贝就很重要,在这点上,epoll是通过内核于用户空间mmap同一块内存实现的。
注:第三点貌似有问题. epoll的内核实现中并没有使用到mmap. 示例如下:
在epoll_ctl中,有:
1141 /* 1142 * The following function implements the controller interface for 1143 * the eventpoll file that enables the insertion/removal/change of 1144 * file descriptors inside the interest set. 1145 */ 1146 SYSCALL_DEFINE4(epoll_ctl, int, epfd, int, op, int, fd, 1147 struct epoll_event __user *, event) 1148 { 1149 int error; 1150 struct file *file, *tfile; 1151 struct eventpoll *ep; 1152 struct epitem *epi; 1153 struct epoll_event epds; 1154 1155 DNPRINTK(3, (KERN_INFO "[%p] eventpoll: sys_epoll_ctl(%d, %d, %d, %p)\n", 1156 current, epfd, op, fd, event)); 1157 1158 error = -EFAULT; 1159 if (ep_op_has_event(op) && 1160 copy_from_user(&epds, event, sizeof(struct epoll_event))) 1161 goto error_return;
在epoll_wait中,最终会调到此函数:
945 /* 946 * Is the event mask intersect the caller-requested one, 947 * deliver the event to userspace. Again, we are holding 948 * "mtx", so no operations coming from userspace can change 949 * the item. 950 */ 951 if (revents) { 952 if (__put_user(revents, 953 &events[eventcnt].events) || 954 __put_user(epi->event.data, 955 &events[eventcnt].data)) 956 goto errxit; 957 if (epi->event.events & EPOLLONESHOT) 958 epi->event.events &= EP_PRIVATE_BITS; 959 eventcnt++; 960 }
其中put_user -- Write a simple value into user space. This function may sleep.
copy_to_user,copy_from_user,get_user,put_user函数比较
注:epoll_create中的参数没有什么用
1133 SYSCALL_DEFINE1(epoll_create, int, size) 1134 { 1135 if (size <= 0) 1136 return -EINVAL; 1137 1138 return sys_epoll_create1(0); 1139 }
1. select/poll的缺点
A. 每次调用时重复的从用户态读入参数
B. 每次调用时全量的扫描文件描述符
C. 每次调用开始,将进程加入到每个文件描述符的等待队列,在调用结束后又把进程从等待队列中删除。
D. 在不修改内核的情况下,select最多支持1024个文件描述符。
http://www.cppblog.com/API/archive/2013/07/01/201424.html
求教:epoll的ET模式对EPOLLOUT事件怎么处理的?
有关epoll的EPOLLOUT
三种使用场景:
1: 对客户端socket只使用EPOLLIN(读)监听,不监听EPOLLOUT(写),写操作一般使用socket的send操作
2:客户端的socket初始化为EPOLLIN(读)监听,有数据需要发送时,对客户端的socket修改为EPOLLOUT(写)操作,这时EPOLL机制会回调发送数据的函数,发送完数据之后,再将客户端的socket修改为EPOLL(读)监听
3:对客户端socket使用EPOLLIN 和 EPOLLOUT两种操作,这样每一轮epoll_wait循环都会回调读,写函数,这种方式效率不是很好