poll,select与epoll

select的参数类型fd_set没有将文件描述符和事件绑定,它仅仅是一个文件描述符集合,因此select需要提供3个这种类型的参数来分别传入和输出可读,可写及异常等事件.这一方面使得select不能处理更多类型的事件,另一方面由于内核对fd_set集合的在线修改,应用程序下次调用select前不得不重置这3个fd_set集合

poll的参数类型pollfd则多少"聪明"一些.它把文件描述符和事件都定义其中,任何事件都被统一处理,从而使得编程接口简洁得多.并且内核每次修改的是pollfd结构体的revents成员,而events成员保持不变,因此下次调用poll时应用程序无须重置pollfd类型的事件集参数.由于每次select和poll调用都返回整个用户注册的事件集合(其中包括就绪和未就绪的),所以应用程序索引就绪文件描述符的时间复杂度O(n).

epoll则采用与select和poll完全不同的方式来管理用户注册的事件.它在内核中维护一个事件表,并提供了一个独立的系统调用epoll_ctl来控制往其中添加,删除,修改事件.这样,每次epoll_wati调用都直接从该内核事件表中取得用户注册的事件,而无须反复从用户空间读入这些事件.epoll_wait系统调用的events参数仅用来返回就绪的事件,这使得应用程序索引就绪文件描述符的时间复杂度的O(1).

从实现原理上来说,select和poll采用的都是轮询的方式,即每次调用都要扫描整个注册文件描述符集合,并将其中就绪的文件描述符返回给用户程序,因此它们检测就绪事件的算法的时间复杂度是O(n).epoll_wait则不同,它采用的是回调的方式.内核检测到就绪的文件描述符,将触发回调函数,回调函数就将该文件描述符上对应的事件插入内核就绪事件队列.内核最后在适当的时机将该就绪事件队列中的内容拷贝到用户空间.因此epoll_wait无须轮询整个文件描述符集合来检测哪些事件已经就绪,其算法时间复杂度是O(1).但是,当活动连接比较多的时候,epoll_wait的效率未必比select和poll高,因为此时回调函数被触发得过于频繁.所以epoll_wait适用于连接数量多,但活动连接较少的情况

你可能感兴趣的:(select)