标签:
一. select 模型(apache的常用)
1. 最大并发数限制,因为一个进程所打开的 FD (文件描述符)是有限制的,由 FD_SETSIZE 设置,默认值是 1024/2048 ,因此 Select 模型的最大并发数就被相应限制了。自己改改这个 FD_SETSIZE ?想法虽好,可是先看看下面吧 …
2. 效率问题, select 每次调用都会线性扫描全部的 FD 集合,这样效率就会呈现线性下降,把 FD_SETSIZE 改大的后果就是,大家都慢慢来,什么?都超时了。
3. 内核 / 用户空间 内存拷贝问题,如何让内核把 FD 消息通知给用户空间呢?在这个问题上 select 采取了内存拷贝方法,在FD非常多的时候,非常的耗费时间。
总结为:1.连接数受限 2.查找配对速度慢 3.数据由内核拷贝到用户态消耗时间
二. Epoll模型的提升(nginx的使用)
再来看看 Epoll 的改进之处吧,其实把 select 的缺点反过来那就是 Epoll 的优点了。
①. Epoll 没有最大并发连接的限制,上限是最大可以打开文件的数目,这个数字一般远大于 2048, 一般来说这个数目和系统内存关系很大 ,具体数目可以 cat /proc/sys/fs/file-max 察看。
②. 效率提升, Epoll 最大的优点就在于它只管你“活跃”的连接 ,而跟连接总数无关,因此在实际的网络环境中, Epoll 的效率就会远远高于 select 和 poll 。
③. 内存共享, Epoll 在这点上使用了“共享内存 ”,这个内存拷贝也省略了。
三. Epoll 为什么高效?
Epoll 的高效和其数据结构的设计是密不可分的,这个下面就会提到。
首先回忆一下 select 模型,当有 I/O 事件到来时, select 通知应用程序有事件到了快去处理,而应用程序必须轮询所有的 FD 集合,测试每个 FD 是否有事件发生,并处理事件;代码像下面这样:
1 int res = select(maxfd+1, &readfds, NULL, NULL, 120); 2 if (res > 0) 3 { 4 for (int i = 0; i < MAX_CONNECTION; i++) 5 { 6 if (FD_ISSET(allConnection[i], &readfds)) 7 { 8 handleEvent(allConnection[i]); 9 } 10 } 11 } 12 // if(res == 0) handle timeout, res < 0 handle error
Epoll 不仅会告诉应用程序有I/0 事件到来,还会告诉应用程序相关的信息,这些信息是应用程序填充的,因此根据这些信息应用程序就能直接定位到事件,而不必遍历整个FD 集合。类似的代码可能如下所示:
1 int res = epoll_wait(epfd, events, 20, 120); 2 for (int i = 0; i < res;i++) 3 { 4 handleEvent(events[n]); 5 }
Epoll 关键数据结构
前面提到 Epoll 速度快和其数据结构密不可分,其关键数据结构就是:
1 struct epoll_event { 2 __uint32_t events; // Epoll events 3 epoll_data_t data; // User data variable 4 }; 5 typedef union epoll_data { 6 void *ptr; 7 int fd; 8 __uint32_t u32; 9 __uint64_t u64; 10 } epoll_data_t;
可见 epoll_data 是一个 union 结构体 , 借助于它应用程序可以保存很多类型的信息 :fd 、指针等等。有了它,应用程序就可以直接定位目标了。
select模型的内核必须遍历所有监视的描述符,而应用程序也必须遍历所有描述符,检查哪些描述符已经准备好。当描述符成百上千时,会变得非常低效——这是
select(poll)模型低效的根源所在。考虑这些情况,2.6以后的内核都引进了epoll模型。
比较一下Linux下的Epoll模型和select模型的区别
标签:
原文地址:http://www.cnblogs.com/shangzekai/p/4626088.html