Epoll

一个服务端同时能够接受多个客户端的链接,每一个链接都是一个SocketChannel(Channel中的一种),这些Channel共同链接到Selector上(服务端仅须要一个选择器),channel会注册感兴趣的事件到Selector中,当调用Select方法返回后,会遍历全部的套接字描述符(服务端进程为每个socket链接建立一个描述符),一旦某个描述符就绪,就通知应用程序进行相应的读写操做。Selector下面会接一个Buffer缓冲区,全部的数据都会先到达内核的缓冲区中,而后再read(汇聚/发散)到用户态应用程序的内存缓冲区中。数组

 

在select中,描述符存放在一个数组中,当调用select()方法的时候,进程会阻塞,直到数组中有某些描述符处于就绪状态,此时select()方法返回,而后遍历该数组,处理这些描述符。select的缺点就是进程能够监视的描述符只有1024个,若是链接数再多的话就不行了。并发

poll的实现和select很是类似,只是描述fd集合的方式不一样。select和poll都须要在返回后,经过遍历文件描述符来获取已经就绪的socket。事实上,同时链接的大量客户端在一时刻可能只有不多的处于就绪状态,所以随着监视的描述符数量的增加,其效率也会线性降低。异步

 

epoll提供了三个函数,epoll_create,epoll_ctl和epoll_wait,epoll_create是建立一个epoll句柄,epoll_ctl是注册要监听的事件类型;epoll_wait则是等待事件的产生。epoll的优势是不受描述符数量的限制,可以支持很是高的并发请求。epoll方式在每一个描述符上定义了一个回调函数,只有当就绪的描述符才会执行回调函数,加入就绪队列中等待应用程序去处理,而不须要每次都遍历fd容器。若是没有大量的idle -connection或者dead-connection,epoll的效率并不会比select/poll高不少,可是当遇到大量的idle-connection,就会发现epoll的效率大大高于select/poll。socket

epoll高效的原理是利用了就绪队列和红黑树:将注册的事件插入到红黑树中,这样每次操做系统找就绪的事件就比较快,找到后就链到就绪队列的链表中,这样每次epoll_wait 就只处理就绪队列的事件,比起poll和 select每次所有遍历一遍高效的多。函数

 

select,poll,epoll都是IO多路复用的机制,该机制能够监视多个描述符,一旦某个描述符就绪,可以通知程序进行相应的读写操做。select,poll,epoll本质上都是同步I/O,由于他们都须要在读写事件就绪后本身负责进行读写,也就是说这个读写过程是阻塞的,而异步I/O则无需本身负责进行读写,异步I/O的实现会负责把数据从内核拷贝到用户空间。操作系统

 

传统IO中,IO线程和event_process(事件处理)线程是在一块儿的,也就是来多少socket链接,就要开多少线程去读写IO并处理该请求。若是有不少的长链接,可是大多socket链接处于idle-connection或者dead-connection状态,那么这些线程都须要持续保留,浪费系统资源。线程

IO多路复用,将IO线程和事件处理线程区分开,事件处理线程放在一个线程池中,而IO线程只有一个,即Selector线程.只有就绪的描述符才会被线程池(事件处理线程)处理掉,其余链接上可是未就绪的描述符,不用专门去开线程维护。blog

相关文章
相关标签/搜索