select和poll都是 IO 多路复用的实现机制,用于监视多个文件描述符的状态变化,以实现高效的 IO 操作。它们的区别如下:
- 数据结构select:使用fd_set结构体来表示文件描述符集合,分别有读、写和异常三个fd_set集合来分别传入和传出可读、可写及异常事件2。poll:使用struct pollfd结构体数组来存放被监听的文件描述符,把文件描述符和与其关联的事件都定义在这个结构体中,编程接口更简洁2。
- 文件描述符数量限制select:有最大文件描述符数量的限制,通常是 1024 个(可以通过修改宏定义等方式改变,但会受到系统资源等限制)4。poll:理论上没有文件描述符数量的限制,它只受限于系统的内存和进程能打开的最大文件描述符数4。
- 就绪文件描述符的获取方式select:调用select函数后,需要通过FD_ISSET宏来遍历fd_set集合中的所有文件描述符,以判断哪些文件描述符就绪,时间复杂度为 O (n)1。poll:poll函数返回后,可以通过检查pollfd结构体数组中revents成员来获取就绪的文件描述符,不需要像select那样遍历整个集合,但仍然需要遍历整个pollfd数组,时间复杂度也是 O (n)2。不过,由于poll把文件描述符和事件绑定在一起,且events成员在调用后保持不变,所以相比select在这方面稍高效一些。
- 超时精度2select:对于超时时间提供了更好的精度,为微秒级。poll:超时精度为毫秒级。
- 水平触发特性1select:只支持水平触发(LT)模式。在水平触发模式下,如果一个文件描述符上的事件没有被处理,下次select调用时仍然会通知该事件。poll:支持水平触发模式,并且新增了水平触发的特性。即通知程序fd就绪后,这次没有被处理,那么下次poll的时候会再次通知同一个fd已经就绪。
总体而言,poll在一定程度上对select进行了改进,如取消了文件描述符数量的限制、编程接口更简洁等,但它们在本质上都是通过轮询的方式来检查文件描述符的状态,在处理大量文件描述符时效率相对较低,不如epoll等基于事件通知机制的 IO 多路复用技术。