unix 中的五种 IO 模型

unix 中的五种 IO 模型

  • 阻塞式 I/O
  • 非阻塞式 I/O
  • I/O 多路复用
  • 信号驱动式 I/O
  • 异步 I/O (POSIX 的 aio_系列函数)

阻塞式 I/O

image-20230708100402340

当采用阻塞式时,必须等待任务处理完成才能继续。其整体的逻辑是链式的

非阻塞式IO

image-20230708101215320

当采用非阻塞时,需要消耗 CPU 去做轮询的工作来得知任务是否处理完成,适用于多个不同类型任务的机制,但是采用 recvfrom 轮询的方式,不但消耗了 cpu 资源,也会增加代码的复杂度。

I/O 多路复用

I/O 多路复用应用非常广泛,这里重点介绍一下:

IO 多路复用是一种高效的编程模型,用于同时监控多个 IO 的可读,可写或异常状态,从而实现在单个线程中处理多个 IO 任务的能力。它通常用于网络编程中,以提高程序的并发性和性能。

image-20230708102943500

select 是阻塞的,可以监听多个文件句柄,当某一个文件句柄的状态发生变化时,会立即返回。

信号驱动式 IO

image-20230708103516479

异步 IO

image-20230708104117935

其相对于 IO 多路复用而言,少了将数据从内核复制到用户空间的步骤,节省了时间

select\poll\epoll

selectpollepoll是用于实现IO多路复用的系统调用或函数。它们在不同的操作系统中提供了类似的功能,允许程序同时监视多个IO对象的状态。

这些IO多路复用机制在网络编程中经常使用,特别是在服务器端的开发中,以处理大量并发的IO操作。它们允许程序同时监听多个套接字的可读、可写或异常状态,并在其中至少有一个套接字就绪时通知应用程序进行相应的处理。

下面是对selectpollepoll的简要解释:

  1. selectselect是最古老和最常见的IO多路复用机制之一。它使用三个文件描述符集合(读、写和异常)来检查多个IO对象的状态。然后,它会阻塞等待,直到其中至少一个IO对象就绪或达到超时时间。然后,它返回就绪的IO对象,应用程序可以对其进行相应的操作。**select在每次调用时都需要重新构建文件描述符集合,效率较低。**
  2. pollpoll是相对于select更现代和高效的IO多路复用机制。类似于selectpoll使用一个文件描述符数组来检查多个IO对象的状态。select不同的是,poll不需要重新构建文件描述符集合,可以直接使用数组,从而提高了效率。它也能够处理更大的文件描述符数量。
  3. epollepoll是在Linux系统中提供的高效的IO多路复用机制。它引入了三个主要的概念:epoll_createepoll_ctlepoll_waitepoll_create用于创建一个epoll对象,epoll_ctl用于向epoll对象注册或删除IO对象,epoll_wait用于等待IO对象就绪。与selectpoll不同,epoll使用了事件驱动的方式,只通知就绪的IO对象,从而避免了遍历整个IO对象集合的开销,提高了性能和扩展性。它还支持边缘触发(edge-triggered)和水平触发(level-triggered)两种模式。

需要注意的是,这些IO多路复用机制的具体使用和细节可能因操作系统而异。在选择使用哪个机制时,需要考虑操作系统的支持、应用程序的需求以及性能等因素。对于大多数情况,epoll在Linux系统中通常是最佳选择,因为它提供了更高的性能和扩展性。

简单概括:

select 函数监听的文件描述符分为三类,分别是 writefds、readfds 和 exceptfds。调用后 select 函数会阻塞,直到有描述符就绪(有数据 可读、可写、或者有 except)或者超时(timeout 指定等待的时间,如果立即返回设置为 null 即可),函数返回。当 select 函数返回后,可以 通过遍历 fdset,来找到就绪的描述符。

select 目前几乎在所有平台上都支持,其良好的跨平台支持也是它的一个优点。select 的一个缺点在于单个进程能够监视的文件描述符的数量存在最大限制,在 linux 上一般为 1024,可以通过修改宏定义甚至重新编译内核的方式提升这一限制,但是这样也会造成效率的降低。

epool 是在 2.6 内核中提出的,是之前的 select 和 poll 的增强版本。相对于 select 和 poll 而言,epoll 更加灵活,没有描述符限制。epoll 使用一个文件描述符对象来管理多个描述符,将用户关系的文件描述符的事件存放于内核的一个事件表中,这样在用户空间和内核空间的 copy 只需要一次。

epoll 的查询效率非常高,其背后的数据结构是因为其存储结构是一个红黑树实现的。

1
2
3
# epoll 并不一定比 select 好
# 在高并发的情况下,连接活跃数不是很高,epoll 比 select 好
# 并发性不高,同时连接很活跃,select 比 epoll 好
-------------THANKS FOR READING-------------