select、poll、epoll各自的特性、区别和相同点

select的特性

select 是 Linux 系统提供的一种 I/O 多路复用机制,它可以同时监听多个文件描述符的 I/O 事件,从而在单线程模型下处理多个并发连接。其特点如下:

支持异步 I/O:select 可以同时监视多个文件描述符上的 I/O 事件,并在事件发生时通过系统调用通知用户程序,从而实现异步 I/O 操作。
可移植性好:select 的接口简单,直观易用,且具有较好的移植性,可以在不同的操作系统中使用。
适合于小规模连接:由于 select 内核使用了轮询的方式遍历文件描述符,并且每次调用 select 需要将文件描述符集合从用户空间拷贝到内核空间,因此 select 对于大规模连接的场景支持有限,适合小规模连接的处理。
受文件描述符数量限制:select 可以监听的文件描述符数量有限,通常不超过 1024。

总体来说,select 是一种通用、简便的 I/O 多路复用机制,适用于小规模连接和处理简单的并发场景,但对于大规模连接的场景,则会存在性能瓶颈。

poll的特性

poll 是 Linux 系统提供的一种 I/O 多路复用机制,与 select 类似,它可以同时监听多个文件描述符的 I/O 事件。相对于 select,poll 有以下特点:

没有文件描述符数量限制:poll 没有监听文件描述符数量的限制,若内存允许,可以监听大规模连接。
可移植性好:poll 的接口较为简单,容易理解和使用,而且支持在不同的操作系统中使用,具有良好的可移植性。
支持异步 I/O:poll 也支持异步 I/O,监视多个文件描述符的 I/O 事件,并在事件发生时通知用户程序,实现异步 I/O 操作。
拷贝文件描述符集合:与 select 类似,每次调用 poll 也需要将文件描述符集合从用户空间拷贝到内核空间,可能存在数据拷贝等各种性能问题。

总体来说,poll 是一种通用、简单的 I/O 多路复用机制,相对于 select,poll 可以更好地处理大规模连接,但由于在文件描述符集合中存在拷贝等问题,对于大量连接仍有一定的性能问题。

epoll的特性

Linux 中的 epoll 是一种高效的 I/O 多路复用机制,相比于传统的 select 和 poll,它具有以下几个特性:

支持大规模文件描述符:在支持 1024 个文件描述符的系统中,使用 select 或 poll 等函数,需要用户将要监听的文件描述符复制到内核中,这样,内核会消耗大量的开销来维护多个文件描述符这样的数组。而 epoll 则没有这种限制,支持 100 万个并发连接,即使对于大型 Web 服务器也保持着高效率。
更快的 I/O 进行队列:在内核空间中维护了一个红黑树和一个链表来记录所有的 epoll 对象、事件。并且采用了回调函数直接把满足条件的事件进行处理,避免了轮询或者遍历整个数据结构的过程,从而避免不必要的计算和拷贝开销,提高了效率。
较少的内核内存拷贝:epoll 底层支持零拷贝,只有在数据报已经就绪时,才将数据从内核缓冲区拷贝到用户空间,在应用程序中避免了多次的内核-用户态间的内存拷贝,提高了效率。
支持两种工作方式:边缘触发(Edge-Triggered,简称ET)和水平触发(Level-Triggered,简称LT),这意味着 epoll 既支持阻塞(Block)工作方式,也支持非阻塞(Non-Block)工作方式。
使用简单:只有三个 API 函数 - epollcreate、epollctl 和 epoll_wait,并且与 select 和 poll 类似,为开发人员提供了一致的使用方式和语法。

总体上讲,epoll 具备更高效、支持大规模文件描述符、较少的系统调用、零拷贝和简便使用等优点,成为了 Linux 下进程间消息传递机制中不可或缺的一种。

三者的区别和共同点

select、poll 和 epoll 是 Linux 系统中提供的三个 I/O 多路复用机制,它们都可以用来同时监听多个文件描述符上的 I/O 事件,从而避免了使用多线程或多进程的开销和复杂性。它们的区别和相同点如下:

相同点:

都是 Linux 系统提供的 I/O 多路复用机制,用于同时处理多个文件描述符上的 I/O 事件。
都是可移植的,可以在不同的操作系统上使用。
都是基于内核事件通知机制实现的,可以通过监听内核事件通知队列来处理文件描述符上的 I/O 事件。

不同点:

功能不同:select 可以监听的文件描述符数量有限,而且每次调用时需要通过参数传递很多信息;poll 可以监听的文件描述符数量稍微多一些,但是也需要通过参数传递文件描述符表;epoll 可以监听的文件描述符数量非常多,而且能够双向扫描,具有更高的效率。
内核实现不同:select 和 poll 的实现方式与内核版本有关,而且对于每个文件描述符,内核都需要检查一遍所有的监听者(即调用 select() 或 poll() 的进程);而 epoll 利用了 Linux 2.6 内核引入的 epoll 事件通知机制,能够避免内核遍历监听者列表的问题,具有更高的效率。
数据拷贝不同:select 和 poll 都需要将监听的文件描述符集合从用户空间拷贝到内核空间,每个事件需要系统调用一次,效率较低;而 epoll 利用了内核 epoll 的事件通知机制,能够避免这个问题,不需要每次都进行数据拷贝。
接口不同:select() 和 poll() 的接口相对简单,只需要通过一些标志位来设置需要监听的 I/O 事件类型和一些特定的参数;而 epoll 的接口更加复杂,需要调用多个不同的函数来完成实例的创建、文件描述符的添加和监听,以及返回已发生事件的文件描述符等操作。

总体来说,select、poll 和 epoll 在实现原理和效率上存在明显的差异。select 和 poll 的缺点在于文件描述符数量有限、效率较低,而 epoll 的优势在于能够监听大量的文件描述符并具有更高的效率。因此,在需要同时处理大量连接的场景下,epoll 比 select 和 poll 更为适用。

你可能感兴趣的:(linux,c++,网络)