面试八股文攻略(四)—— IO 模型

一、基本概念

计算机对数据的读写处理。

二、IO 模型的种类

2.1 阻塞 IO 模型

概念

进程发起IO系统调用后,进程被阻塞,转到内核空间处理,整个IO处理完毕后返回进程,操作成功则进程获取到数据。阻塞期间进程中断。

优点:

实现简单

缺点:

效率低且并发性差

2.2 非阻塞 IO 模型

概念

进程发起IO系统调用后,如果内核缓冲区没有数据,需要到IO设备中读取,进程返回一个错误而不会被阻塞。进程发起IO系统调用后,如果内核缓冲区有数据,内核就会把数据返回进程。

优点:
  1. 非阻塞IO可以提高程序的并发性能。在读写IO操作时,进程不会被阻塞,可以进行其他操作,从而充分利用CPU资源,提高并发性能。
  2. 非阻塞IO可以释放进程,提高程序效率。因为非阻塞 IO 不需要进程一直在等待。
缺点:
  1. 非阻塞IO模型程序实现复杂。由于非阻塞IO编程需要通过轮询IO操作是否完成等方式,因此程序实现复杂,需要编写较多的代码。
  2. 系统调用返回值不确定。非阻塞IO模型中,系统调用的返回值并不是一定的,需要通过errno等方式来判断具体的错误信息,这也增加了程序的复杂度。
  3. 可能会浪费CPU资源。当轮询IO操作的时间间隔过长时,会导致系统出现空转的现象,浪费CPU资源。

2.3 IO 复用模型

概念

多路复用IO是指通过一个线程来处理多个IO请求,通过select、poll、epoll等系统调用来监听多个IO对象是否有可读可写事件。多路复用IO模型可以同时处理多个IO请求,并且不需要进行IO轮询,效率更高。

流程

首先初始化监听的文件描述符集合,然后不断调用系统调用来监听事件并处理IO操作,最后再将文件描述符集合从监听队列中删除。

优点
  1. 多路复用IO可以通过异步IO的方式,避免阻塞等待IO的返回结果,从而可以更高效的利用CPU,提高系统的性能。
  2. 多路复用IO可以让应用程序同时监听多个文件描述符事件,从而减少系统调用的次数,大大提高程序的并发性能,从而提高系统的吞吐量,减少资源占用和等待时间。
缺点
  1. 多路复用IO模型的实现比阻塞IO模型更加复杂,需要更多的代码和时间来完成。
  2. 多路复用IO模型在处理大量连接时,可能会出现性能瓶颈,限制系统的并发处理能力,而且处理效率可能会随着客户端连接数增加而降低。
  3. 多路复用IO模型在处理长连接时,可能会出现资源浪费的情况。因为多路复用IO需要不断轮询事件,所以会对系统CPU和内存等资源产生一定的负担。

2.4 信号驱动的IO模型

概念

当进程发起一个IO操作,会向内核注册一个信号处理函数,然后进程返回不阻塞;当内核数据就绪时会发送一个信号给进程,进程便在信号处理函数中调用IO读取数据。

优点
  1. 信号驱动的IO模型可以不用轮询来等待IO事件的通知,而是通过信号方式来等待事件的通知,从而避免轮询造成的资源浪费。
  2. 信号驱动的IO模型能够实现对文件描述符的异步IO操作,不必挂起进程等待IO操作的完成,从而能够提高系统的并发性和效率。
  3. 信号驱动的IO模型能够从信号处理函数中快速地响应IO事件,从而减少了系统调用的次数,提高了应用程序的性能。
缺点
  1. 信号驱动的IO模型的实现机制复杂,编程难度大,容易出现程序中的错误。
  2. 信号驱动的IO模型只能够同时监听有限的文件描述符,当应用程序需要同时监听大量的文件描述符时,性能会下降。
  3. 信号驱动的IO模型可能会出现信号处理函数与应用程序的其他部分竞争系统资源,从而影响性能。

2.5 异步 IO 模型

概念

当进程发起一个IO操作,进程返回(不阻塞),但也不能返回结果。内核把整个IO处理完后,会通知进程结果,如果IO操作成功则进程直接获取到数据。
前四个模型从内核空间拷贝数据这一过程是阻塞的,需要自己把准备好的数据,放到用户空间。
而全异步不同,异步IO是「内核数据准备好」和「数据从内核态拷贝到用户态」这两个过程都不用等待。

优点
  1. 异步IO模型能够提高系统的并发处理能力和效率,因为它的IO操作在发起之后就可以立即返回,并且在IO操作完成后通过回调函数来通知应用程序执行后续操作,从而实现异步的IO操作。
  2. 异步IO模型可以在进行IO操作时避免阻塞进程,并且可以更加高效地使用CPU资源,从而提高系统的性能。
  3. 异步IO模型可以同时处理多个IO请求,从而提高应用的并发性和吞吐量。
缺点
  1. 异步IO模型在处理较大的数据量或者处理过程中需要进行复杂的协作时,可能会出现代码逻辑的复杂度增加,导致代码难以维护的问题。
  2. 异步IO模型在工作队列中可能会出现大量的IO请求,从而导致性能上的瓶颈,需要进行更加细致的线程池和事件驱动处理等。

三、 IO 复用的具体实现逻辑

3.1 Select 函数

Select 是一个 linux 的系统调用函数。传参为可读的文件描述符集合 readfds 和 可写的文件描述符集合 writefds以及异常的文件描述符集合 exceptfds 还有过期时间。

具体步骤
  1. 将待监视的文件描述符添加到对应的文件描述符集合中。可以通过调用FD_ZERO和FD_SET宏来创建和设置文件描述符集合。

  2. 调用select函数开始轮询等待文件描述符是否就绪。当任何一个文件描述符集合中有文件描述符就绪时,select函数就会返回。

  3. 在select函数返回之后,需要遍历所有三个集合来查找哪些文件描述符已经就绪了。可以通过调用FD_ISSET宏来检查集合中的特定文件描述符是否就绪。

  4. 对于每一个就绪的文件描述符,进行相应的IO操作处理。

优点

可移植性:select 函数是标准 C 的一部分,并且在各种系统下都能够使用。

高效性:select 函数允许同时监视多个文件描述符,因此可以更高效地处理大量并发的网络连接。

灵活性:select 函数可以同时监视三个文件描述符集合,包括读、写、异常,因此可以更灵活地操作多个文件描述符。

事件驱动:select 函数是事件驱动模型的核心,充分利用了计算机事件和 I/O 的特性,能够有效地提高应用程序的吞吐量。

缺点

低效性:select 函数每次调用都需要将待检查的文件描述符集合从用户空间复制到内核空间,这种复制造成了一定的开销,并且在文件描述符集合比较大的情况下,开销将更加显著,因此 select 在处理大量并发连接时可能不太适用。

最大文件描述符数限制:在 win32 架构下,select 函数对于待监视的文件描述符数目有限制,可能会导致无法处理所有的并发连接。

只适用于可读可写:select 函数只能监视可读和可写两种事件,无法监视其他类型的事件。虽然很多情况下这已经足够了,但在某些特殊的网络应用场景中可能无法满足需求。

3.2 Poll 函数

Poll 函数使用 pollfd结构体组成的数组进行文件的调用,解决了 select 函数使用了 fd_set 结构体受限于位数组长度的问题。 pollfd 结构体中包含了 fd 文件描述符, event 监测的事件和 revent 实际发生的时间类型(内核负责填充)。

同时, Poll 数组在内核中使用了链表 + 红黑树存储文件描述符,不需要遍历全部。而 select 函数是轮询所有的文件,效率较低。

3.3 Epoll 函数

首先,epoll 和 select/poll 最大的不同在于它采用了事件通知的机制,因此它避免了 select 和 poll 的“轮询”(polling),使得在大量并发连接时,epoll 的效率比 select/poll 高很多。

其次,epoll 构建了一个由内核维护的事件表,这个事件表是一个红黑树,红黑树的键就是文件描述符,值是 epoll_event 结构体。epoll_event 结构体包含有两个成员变量:events 和 data。

再次,通过 epoll_ctl 函数向内核注册感兴趣的事件,从而将文件描述符和事件对应的 epoll_event 结构体加入到内核事件表中。当某个事件与感兴趣的事件匹配时,内核会将这个事件加入到 epoll_wait 函数的返回结果中,通知应用程序进行处理。

最后,当调用 epoll_wait 函数时,内核会检查需要监控的socket有没有事件发生,若有,就会将事件加入到就绪事件队列中,等待进程来处理。但是需要注意,事件通知在第一次触发后就会被清除,这样下一次 epoll_wait 就只能等待下一个事件的产生了。

四、 Reactor 模式和 Proactor 模式

4.1 不同

事件处理方式不同

Reactor 模式采用的是同步事件处理方式,即事件触发后立即处理事件,而 Proactor 模式采用的是异步事件处理方式,即事件触发后通知应用程序,由应用程序进行事件处理。

适用场景不同

Reactor 模式适用于高并发连接少,但连接活跃度高的场景,如 Web 服务器。而 Proactor 模式适用于高并发连接多,但连接活跃度低的场景,如数据库服务器。

实现复杂度不同

Reactor 模式需要应用程序负责处理 I/O 事件,需要考虑线程同步和 IO 复用等问题,实现比 Proactor 模式复杂。而 Proactor 模式相对来说更容易实现,应用程序只需要提供回调函数即可。

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值