Select,poll,epoll和IO多路复用和NIO
-
IO 多路复用:是一种 I/O 处理机制,它允许单个线程同时处理多个 I/O 流(如多个文件描述符对应的网络连接、文件操作等)的输入输出操作,通过一种机制来监听这些 I/O 流的状态变化(如可读、可写等),一旦某个 I/O 流有状态变化,就可以对其进行相应的处理。Select、Poll、Epoll 都是实现 IO 多路复用的具体技术手段,它们属于 IO 多路复用这个大的范畴。
-
NIO(New Input/Output):是 Java 中对传统 I/O(BIO,Blocking I/O)的一种改进,它提供了非阻塞 I/O 和基于通道(Channel)与缓冲区(Buffer)的 I/O 操作方式等特性。NIO 在实现过程中也会用到 IO 多路复用的思想,并且在 Java 的 NIO 实现中,底层实际上是可以基于 Select、Poll 或 Epoll(取决于不同的操作系统和 Java 运行时环境)等方式来实现对多个 I/O 事件的监听和处理,所以 NIO 与 IO 多路复用紧密相关,它是在 Java 语言层面应用 IO 多路复用机制的一种体现。
Select,poll,epoll区别
他们是NIO中多路复用的三种实现机制,是由Linux操作系统提供的。
用户空间和内核空间: 操作系统为了保护系统安全,将内核划分为两个部分,一个是用户空间,一个是内核空间。用户空间不能直接访问底层的硬件设备,必须通过内核空间。
文件描述符 File Descriptor(FD): 是一个抽象的概念,形式上是一个整数,实际上是一个索引值。指向内核中为每个进程维护 进程所打开的文件的记录表。当程序打开一个文件或者创建一个文件时,内核就会向进程返回一个FD。Unix,Linux中才有
select机制: 会维护一个FD的结合 fd_set,将fd_set从用户空间复制到内核空间,激活socket。 x64位机器上受限 2048, fd_set是一个数组结构
Poll机制: 和selecter机制是差不多的,把fd_set结构进行了优化,FD集合的大小就突破了操作系统的限制。 pollfd结构来代替fd_set,通过链表实现的。操作跟Selecter机制一样都是遍历FD集合
EPoll: Event Poll.Epoll不再扫描所有的FD,只将用户关心的FD的事件存放到内核的一个事件表当中。这样,可以减少用户空间与内核空间之前需要拷贝的数据
-
Select,poll,epoll都是底层C++的API
java的NI0当中是用的那种机制?
可以查看DefaultSelectorProvider类的源码,
在windows下,WindowsSelectorProvider. 而Linux下,根据Linux的内核版本,2.6版本以上,就是EPollSelectorProvider,否则就是默认的PollSelectorProvider.
1. Select
-
实现原理:Select 通过一个文件描述符集合fd_set(通常有三个集合,分别对应可读、可写和异常事件)来监听多个 I/O 流的状态变化。在调用 Select 函数时,它会遍历这个集合中的所有文件描述符,逐个检查它们是否有对应的可读、可写或异常事件发生。如果有事件发生,Select 会返回,并告知哪些文件描述符发生了何种事件,然后程序就可以针对这些发生事件的文件描述符进行相应的处理。
-
性能特点:
-
随着监听的文件描述符数量增加,性能会显著下降。因为每次调用 Select 都需要遍历整个文件描述符集合来检查状态变化,当文件描述符数量很大时,遍历的开销就会变得很大。
-
每次调用 Select 后,返回的结果只是告知哪些文件描述描述符有事件发生,但并没有提供详细的事件信息,例如对于可读事件,它不会告诉你到底有多少数据可读,还需要进一步通过读取操作来确定。
-
-
平台支持:Select 是最早1984年出现的 IO 多路复用技术,几乎在所有的操作系统上都有支持,具有很好的跨平台性。
2. Poll
-
实现原理:Poll 的工作原理与 Select 类似,也是通过一个结构体数组pollfd(类似文件描述符集合)来监听多个 I/O 流的状态变化。不同的是,Poll 使用的结构体数组可以动态分配大小,不像 Select 那样有固定大小的集合限制。在调用 Poll 函数时,同样会遍历这个结构体数组来检查各 I/O 流的状态变化,一旦有事件发生,Poll 会返回并告知相关信息。
-
性能特点:
-
虽然 Poll 解决了 Select 文件描述符集合固定大小的问题,但它在性能上与 Select 类似,当监听的文件描述符数量较多时,遍历结构体数组的开销同样会导致性能下降。
-
与 Select 一样,返回的结果也只是告知哪些文件描述符有事件发生,没有提供更详细的事件信息,需要进一步操作来确定具体情况。
-
-
平台支持:Poll 也具有较好的跨平台性,在很多操作系统上都有支持,不过在实际应用中,由于性能方面的原因,使用频率相对 Select 可能会低一些。1997年
3. Epoll
-
实现原理:Epoll 是 Linux 特有的一种高性能的 IO 多路复用技术。它采用了事件驱动的设计思想,通过在内核中创建一个红黑树来管理所有监听的文件描述符,同时还有一个就绪队列来存放已经发生事件的文件描述符。当有事件发生时,内核会直接将发生事件的文件描述符放入就绪队列,而不是像 Select 和 Poll 那样需要遍历整个集合或数组来查找。应用程序只需要从就绪队列中获取发生事件的文件描述符并进行处理即可。
-
性能特点:
-
具有非常高的性能,尤其是在监听大量文件描述符时优势明显。因为它不需要遍历所有监听的文件描述符来查找发生事件的文件描述符,大大减少了遍历开销。
-
提供了更详细的事件信息,例如对于可读事件,它可以告知有多少数据可读等详细情况,这使得应用程序在处理 I/O 事件时更加高效。
-
-
平台支持:Epoll 仅在 Linux 操作系统上有支持,不具有跨平台性。
4. NIO(从 Java 角度看)
-
实现原理:Java 的 NIO 基于通道(Channel)和缓冲区(Buffer)进行 I/O 操作。它提供了非阻塞 I/O 模式,即当进行读或写操作时,如果没有数据可读或可写,不会像传统的 BIO 那样阻塞等待,而是立即返回并告知当前状态。在监听多个 I/O 事件方面,Java 的 NIO 底层会根据不同的操作系统采用不同的 IO 多路复用实现方式(如在 Linux 下可能采用 Epoll,在 Windows 下可能采用类似 Select 的实现,在 Mac OS 等其他操作系统下也有相应的实现方式),通过这些方式来实现对多个 I/O 通道的监听,一旦某个通道有事件发生,就可以进行相应的处理。
-
性能特点:
-
相比于传统的 BIO,NIO 的非阻塞特性使得它在处理多个 I/O 事件时可以更高效地利用系统资源,减少了因阻塞等待而浪费的时间。
-
不过,NIO 的实现相对复杂一些,尤其是在处理复杂的 I/O 场景时,需要对通道、缓冲区以及事件监听等方面有较好的理解和运用。
-
-
平台支持:Java 的 NIO 具有良好的跨平台性,因为它会根据不同的操作系统采用合适的底层 IO 多路复用实现方式来保证在各种操作系统上都能正常运行。
综上所述,Select、Poll、Epoll 是实现 IO 多路复用的不同技术手段,各有其性能特点和适用场景,而 NIO 是 Java 中应用 IO 多路复用思想的一种实现,它与这些 IO 多路复用技术紧密相关,并且在不同的操作系统下会依托不同的 IO 多路复用实现方式来实现其功能。