浅析I/O多路转接poll技术
上篇博客I/O多路转接select技术笔者已经为大家详细介绍了select函数的使用方式以及特点。我们在文章最后总结的时候我们提到,select虽然已经很大程度上解决了I/O过程中等待的问题,但是由于函数本身接口设计的不友好、能够检测的文件描述符有上限,以及函数多次循环遍历的效率问题导致select在实际场景中并不是使用的那么广泛。
今天我们要介绍的poll函数从一定程度上对select进行了优化,那么具体是怎么优化的,让我们一探究竟。
poll函数
int poll(struct pollfd *fds, nfds_t nfds, int timeout);
参数介绍:
- fds:这个参数是struct pollfd类型的结构体指针,结构体中存放关于要关心时间文件描述符的一些东西
- nfds:表示第一个参数数组的大小
- timeout:超时时间设置,单位为毫秒。设置为0表示非阻塞式等待,大于零表示在等待n毫秒之后超时返回,-1则表示阻塞式等待
struct pollfd:在/usr/include/asm-generic/poll.h头文件下成功找到了这个结构体
- fd:表示你要关心那个文件描述符
- events:一个位图,每一个位置对应了你所关心的事件
- revents:同样是位图,此位图中poll函数帮我们设置已经就绪的事件
事件有:这些事件events和revents都会发生
事件 | 描述 |
---|---|
POLLIN | 有数据可读 |
POLLRDNORM | 有普通数据可读 |
POLLRDBAND | 有优先数据可读 |
POLLPRI | 有紧迫数据可读 |
POLLOUT | 写数据不会导致阻塞 |
POLLWRNORM | 写普通数据不会导致阻塞 |
POLLWRBAND | 写优先数据不会导致阻塞 |
POLLMSGSIGPOLL | 消息可用 |
只发生在revents中的额外事件:
事件 | 描述 |
---|---|
POLLER | 指定的文件描述符发生错误 |
POLLHUP | 指定的文件描述符挂起事件 |
POLLNVAL | 指定的文件描述符非法 |
从上面的介绍中来看,仅从函数签名就能发现poll比select函数友好很多。这里poll函数将自己的所关心的事件全部整合在一起,设置时往events位图中设置,而条件就绪时则使用revents位图设置返回。
select和poll对比
看了poll函数你就会发现,poll函数其实是select函数的优化版本。select函数和poll函数相比并没有优点,poll函数的出现很大程度上是用来弥补select函数的缺点的,那么poll函数到底相比select进行了哪些优化呢?
- 参数分离:select实际上将输入输出参数混为一谈,所以也就导致必须使用额外的数组来保存要关注的文件描述符。每经过一轮处理就需要重新遍历数组进行再次设置,这极大影响了效率。而poll函数使用pollfd数组的方式将这些要关心的文件描述符管理起来,这就避免了每经过一次处理后下次检测之前重新设置的缺点
- 文件描述符无上限:俗话说人有多大胆,地有多大产。poll并没有规定所能检测文件描述符的最大上限,虽然函数参数要传一个固定值,但是这个固定值只要系统能处理过来,多大都可以
poll函数的缺点
poll函数优化了参数和文件描述符上限的问题,可是我们要想明白使用多路转接技术到底是为了什么。多路转接就是为了优化阻塞式I/O等待时间较长的问题,而poll只优化了上面的俩点好像并没有让效率提高很多。
poll和select的共同问题:
- 问题一:poll和select一样,每次关心这些事件时都要拷贝大量数据到内核态。select拷贝fd_set位图,poll拷贝pollfd数组
- 问题二:每次事件就绪后你并不知道这些文件描述符中到底是哪个文件描述符上的事件就绪,所以不管是select还是poll都需要循环遍历这些位图或者数组来寻找那个已经就绪的描述符
被epoll取代的select和poll
下篇博客我们就要讲多路转接技术最后的主角epoll了,之所以select和poll没有将要谈到的epoll好是因为光从循环遍历这个缺点来看,某种情况下select和poll就是不合格的,举个栗子
- 栗子一:如果现在你的服务器上关心了非常多的文件描述符,但是每次都只有很少的描述符就绪,这就导致就算每次只有一个描述符就绪你都需要返回一次遍历这个特别长的数组
- 栗子二:设想如果马爸爸使用poll函数作为服务器,如果遇到双11这种"中国top级别盛会"访问的高峰时,中国有15亿人口,就算有1亿人访问淘宝,你可以设想多次循环遍历一个一亿个元素长的数组是什么感觉。所以其实poll和select最大的瓶颈就是事件就绪后的循环遍历。
总结
经过select和poll函数的介绍,你会发现这两个函数还是存在一些列的缺点的。下篇博客要谈的epoll函数真的是让人惊艳的设计,今天所提到的问题epoll函数都能解决。那么epoll到底是哪路神仙我们下篇博客见。