当前位置:嗨网首页>书籍在线阅读

10-select()和poll()存在的问题

  
选择背景色: 黄橙 洋红 淡粉 水蓝 草绿 白色 选择字体: 宋体 黑体 微软雅黑 楷体 选择字体大小: 恢复默认

63.2.5 select()和poll()存在的问题

系统调用select()和poll()是用来同时检查多个文件描述符就绪状态的方法,它们是可移植的、长期存在且被广泛使用的。但是当检查大量的文件描述符时,这两个 API 都会遇到一些问题。

  • 每次调用select()或poll(),内核都必须检查所有被指定的文件描述符,看它们是否处于就绪态。当检查大量处于密集范围内的文件描述符时,该操作耗费的时间将大大超过接下来的操作。
  • 每次调用select()或poll()时,程序都必须传递一个表示所有需要被检查的文件描述符的数据结构到内核,内核检查过描述符后,修改这个数据结构并返回给程序。(此外,对于select()来说,我们还必须在每次调用前初始化这个数据结构。)对于poll()来说,随着待检查的文件描述符数量的增加,传递给内核的数据结构大小也会随之增加。当检查大量文件描述符时,从用户空间到内核空间来回拷贝这个数据结构将占用大量的 CPU 时间。对于 select()来说,这个数据结构的大小固定为FD_ SETSIZE,与待检查的文件描述符数量无关。
  • select()或poll()调用完成后,程序必须检查返回的数据结构中的每个元素,以此查明哪个文件描述符处于就绪态了。

上述要点产生的结果就是随着待检查的文件描述符数量的增加,select()和 poll()所占用的CPU时间也会随之增加(更多细节请参见63.4.5节)。对于需要检查大量文件描述符的程序来说,这就产生了问题。

select()和poll()糟糕的性能延展性源自这些 API 的局限性:通常,程序重复调用这些系统调用所检查的文件描述符集合都是相同的,可是内核并不会在每次调用成功后就记录下它们。

我们接下来要讨论的信号驱动I/O以及epoll都可以使内核记录下进程中感兴趣的文件描述符,通过这种机制消除了select()和poll()的性能延展问题。这种解决方案可根据发生的I/O事件来延展,而与被检查的文件描述符个数无关。结果就是,当需要检查大量的文件描述符时,信号驱动I/O和epoll能提供更好的性能表现。