select, poll 和 epoll 都是用于 I/O 多路复用的机制,允许一个进程监视多个文件描述符的状态变化。它们在 Linux 系统中都是常见的用于网络编程的工具,但是它们有一些区别:
- select:
- select 是最古老的一种 I/O 多路复用机制,最早出现在 BSD 系统上。
- 它使用一个位图来存储需要监听的文件描述符,存在文件描述符数目限制。
- 每次调用 select 都需要将全部需要监视的文件描述符集合传递给内核,即使只有其中几个文件描述符状态发生了变化。
- 在较小规模的情况下性能表现不错,但是随着文件描述符数量的增加,性能下降明显。
- poll:
- poll 是对 select 的改进,出现在 System V Release 3 上。
- 它采用链表来存储需要监听的文件描述符,解决了 select 中文件描述符数量限制的问题。
- 每次调用 poll 都需要传递一个描述符数组到内核,和 select 类似,但是没有了文件描述符数量的限制。
- epoll:
- epoll 是 Linux 特有的 I/O 多路复用机制,出现在 Linux 2.5.44 内核版本上。
- 它使用了一种基于事件的机制来通知应用程序文件描述符的状态变化,不需要每次都遍历全部的文件描述符。
- epoll 使用了三个系统调用:epoll_create 创建一个 epoll 实例,epoll_ctl 用于添加、修改或删除需要监听的文件描述符,epoll_wait 用于等待文件描述符的状态变化。
- epoll 在大规模并发情况下性能表现优秀,对于数量庞大的文件描述符,其性能不会随着文件描述符数量的增加而下降。
综上所述,epoll 是目前 Linux 系统下性能最好的 I/O 多路复用机制,尤其在处理大规模并发连接时表现突出。
在数据拷贝方面,select、poll 和 epoll 在内核空间到用户空间之间的数据拷贝上有一些区别:
- select 和 poll:
- 在 select 和 poll 中,当文件描述符就绪时,内核会将就绪的文件描述符集合复制到用户空间,然后用户程序需要遍历这个集合来找出哪些文件描述符处于就绪状态。
- 因此,在 select 和 poll 中,存在一次额外的数据拷贝,即从内核空间到用户空间的拷贝。
- epoll:
- 在 epoll 中,用户程序不需要遍历文件描述符集合来找出就绪的文件描述符,而是通过 epoll_wait 系统调用直接获取就绪的文件描述符列表。
- 当调用 epoll_wait 时,内核会将就绪的文件描述符直接填充到用户提供的缓冲区中,避免了额外的一次数据拷贝。
因此,相比于 select 和 poll,epoll 在数据拷贝方面更加高效,减少了一次内核空间到用户空间的数据拷贝操作。