epoll好文章
https://www.cnblogs.com/apprentice89/p/3234677.html
https://www.jianshu.com/p/aa486512e989
https://cloud.tencent.com/developer/article/1005481
最后看看epoll独有的两种模式LT和ET。无论是LT和ET模式,都适用于以上所说的流程。区别是,LT模式下,只要一个句柄上的事件一次没有处理完,会在以后调用epoll_wait时次次返回这个句柄,而ET模式仅在第一次返回。
这件事怎么做到的呢?
当一个socket句柄上有事件时,内核会把该句柄插入上面所说的准备就绪list链表,这时我们调用epoll_wait,会把准备就绪的socket拷贝到用户态内存,然后清空准备就绪list链表,
最后,epoll_wait干了件事,就是检查这些socket,如果不是ET模式(就是LT模式的句柄了),并且这些socket上确实有未处理的事件时,又把该句柄放回到刚刚清空的准备就绪链表了。
所以,非ET的句柄,只要它上面还有事件,epoll_wait每次都会返回。而ET模式的句柄,除非有新中断到,即使socket上的事件没有处理完,也是不会次次从epoll_wait返回的。
epoll为什么使用红黑树
因为epoll要求快速找到某个句柄,因此首先是一个Map接口,候选实现:
哈希表 O(1)
红黑树 O(lgn)
跳表 近似O(lgn)
据说老版本的内核和FreeBSD的Kqueue使用的是哈希表.
个人理解现在内核使用红黑树的原因:
哈希表. 空间因素,可伸缩性.
(1)频繁增删. 哈希表需要预估空间大小, 这个场景下无法做到.
间接影响响应时间,假如要resize,原来的数据还得移动.即使用了一致性哈希算法,
也难以满足非阻塞的timeout时间限制.(时间不稳定)
(2) 百万级连接,哈希表有镂空的空间,太浪费内存.
跳表. 慢于红黑树. 空间也高.
红黑树. 经验判断,内核的其他地方如防火墙也使用红黑树,实践上看性能最优.
fd数量受限于内核内存大小,理论上无限
epoll 跟mmap没关系 没用到mmap
https://www.cnblogs.com/lojunren/p/3856290.html
后面的ETLT区别写得好
LT与ET模式
在这里,笔者强烈推荐《彻底学会使用epoll》系列博文,这是笔者看过的,对epoll的ET和LT模式讲解最为详尽和易懂的博文。下面的实例均来自该系列博文。限于篇幅原因,很多关键的细节,不能完全摘录。
话不多说,直接上代码。
程序一:
#include <stdio.h> #include <unistd.h> #include <sys/epoll.h> int main(void) { int epfd,nfds; struct epoll_event ev,events[5]; //ev用于注册事件,数组用于返回要处理的事件 epfd = epoll_create(1); //只需要监听一个描述符——标准输入 ev.data.fd = STDIN_FILENO; ev.events = EPOLLIN|EPOLLET; //监听读状态同时设置ET模式 epoll_ctl(epfd, EPOLL_CTL_ADD, STDIN_FILENO, &ev); //注册epoll事件 for(;;) { nfds = epoll_wait(epfd, events, 5, -1); for(int i = 0; i < nfds; i++) { if(events[i].data.fd==STDIN_FILENO) printf("welcome to epoll's word!\n"); } } }
编译并运行,结果如下:
- 当用户输入一组字符,这组字符被送入buffer,字符停留在buffer中,又因为buffer由空变为不空,所以ET返回读就绪,输出”welcome to epoll's world!”。
- 之后程序再次执行epo