自学内容网 自学内容网

20250116面试鸭特训营第24天

更多特训营笔记详见个人主页【面试鸭特训营】专栏

250116

1. I/O模型有哪些?

同步阻塞 I/O

  • 调用 I/O 操作时,进程会被阻塞,直到数据准备好或操作完成后才继续执行。

在这里插入图片描述

  • 流程

    • 用户线程调用 read 试图获取网络数据。

    • 用户线程阻塞等待数据的同时,

      1. 网卡获取客户端数据。
      2. 网卡将获得到的数据拷贝到内核中。
      3. 内核将数据拷贝到用户线程中。
    • 用户线程成功获取网络数据。

  • 优点:使用简单,调用 read 后就不管了,直到拿到数据且准备好了,再进行处理。

  • 缺点:同步等待浪费资源,于是有了同步非阻塞 I/O 。

同步非阻塞 I/O

  • I/O 操作不会阻塞进程,如果数据没准备好,立即返回错误或状态,进程可能继续执行其他操作。
  • 从内核拷贝到用户空间的这段时间,用户线程还是会被阻塞。

在这里插入图片描述

  • 流程
    • 用户线程调用 read 试图获取网络数据。
    • 若没有数据,内核直接返回错误,告知用户线程暂无准备就绪的数据,此时用户线程可以先去干别的事情,然后再继续调用 read 看看有没有数据,这个阶段用户线程不会被阻塞
    • 若有数据,在内核将数据拷贝到用户空间的这段时间,用户线程是被阻塞的
  • 缺点
    • 如果用户线程只负责取数据和处理数据这一个任务,没有其他任务,就会不停地进行系统调用。
    • 当用户线程数量变多时,海量线程不断地进行系统调用,但大多数做的又都是无用功,CPU 会因为频繁地无用地上下文切换而崩溃。
    • 于是就有了 I/O 多路复用。

I/O 多路复用

  • 使用 selectpollepoll 等系统调用,允许程序同时等待多个 I/O 操作,当其中任意一个就绪时进行处理。

在这里插入图片描述

  • 多路:多条连接。
  • 复用:用一个线程可以监控多条连接。
  • 同步非阻塞 I/O 的缺点是,用户线程过多时,会造成频繁的上下文切换。
  • 多路复用模型,是招了一个 “专员(select)” ,只用一个线程查看多个链接是否有数据已经准备就绪。
  • 往 select 里面注册需要被监听的链接,由 select 来监控它所管理的链接是否有数据已经准备就绪,如果有,则**【可以】**通知别的线程来 read 读取数据。这个 read 和之前的一样,在内核将数据拷贝到用户空间的这段时间,用户线程被阻塞。
  • 优势:用少量的线程去监控多条连接,减少了线程的数量,降低了内存的消耗且减少了上下文切换的次数。

信号驱动 I/O

  • 在数据准备好时,内核通过信号通知进程进行 I/O 操作,进程在接收信号后再进行数据读取或写入。

在这里插入图片描述

  • 【I/O 多路复用】中不阻塞的 select 轮询,改为 由内核告知数据准备就绪 ,然后用户线程再去 read (read 过程中用户线程阻塞)。

为什么市面上用的都是 I/O 多路复用,而不是信号驱动 I/O?

  • 因为我们的应用程序通常用的都是 TCP 协议,TCP 协议对信号驱动不太友好,但 UDP 协议可以使用信号驱动。
  • TCP 协议事件较多,TCP 协议的 socket 可以产生七种信号事件,不仅仅只有数据准备就绪才会发信号,其他事件也会发信号,但这个信号又是同一个信号,应用程序无法区分到底是什么事件产生的这个信号。
  • UDP 协议事件没那么多,所以可以用信号驱动。

异步 I/O

  • 发起 I/O 请求后立即返回,内核在后台完成 I/O 操作,并在操作完成时通知进程。进程不需要等待 I/O 完成即可继续执行其他任务。

在这里插入图片描述

  • 内核把数据拷贝到用户空间之后再告知用户线程,真正实现完全非阻塞 I/O。
  • 流程
    • 用户线程调用 aio_read
    • 在内核空间内完成【准备数据】、【把数据拷贝到内核】、【把数据拷贝到用户空间】。
    • 通知用户线程获取已经拷贝到用户空间的数据。
    • 用户线程继续执行后续操作。

2. Select、Poll、Epoll 之间有什么区别?

  • Select、Poll、Epoll 都是操作系统中用于多路复用 I/O 的机制。

Select

  • 早期的 I/O 多路复用机制。
  • select 函数使用固定长度的数组表示文件描述符集,将文件描述符的状态(如可读、可写、异常)存储在一个数组中。
  • 每次调用 select 时,程序都需要重新构建文件描述符集,并将所有文件描述符集传递给内核检查状态,判断是否有 I/O 操作就绪。
  • 局限
    • 文件描述符数量有限
      • 通常为1024(可以通过修改系统参数调整),限制了并发处理的数量,在大规模连接的场景下效率较低。
    • 性能低
      • 在高并发场景中,每次都需要遍历整个文件描述符进行检查,性能开销大。
    • 不适合高并发场景
      • 由于每次连接都需要线性扫描整个文件描述符集,随着连接数的增加,select 的效率会急剧下降。

Poll

  • pollselect 类似,但使用动态数组来存储文件描述符,能够支持更多的连接数,没有 select 的最大连接数限制。
  • 每个文件描述符有一个对应的结构体(pollfd),包含文件描述符和事件类型。
  • 调用 poll 时,程序传入的描述符数组会被内核修改,以反映当前文件描述符的状态。
  • 改进
    • 打破文件描述符的数量限制:poll 不再依赖于固定大小的位图数组,可以支持任意数量的文件描述符。
    • 接口更灵活:比 select 更灵活,适合大部分网络应用场景。
  • 不足
    • 每次调用时仍需遍历所有描述符:即使只有少数描述符发生变化,也需要检查整个数组。
    • 性能开销较大:在大规模并发场景下,性能问题依然存在。

Epoll

  • epoll 使用一个内核空间的时间列表,应用程序可以通过 epoll_ctlepoll 实例注册、修改或是删除感兴趣的文件描述符及其事件。
  • 调用 epoll_wait 时,只会返回发生事件的文件描述符,而不是检查所有描述符。
  • epoll 是 Linux 系统对 selectpoll 的优化,提供了**边缘触发(ET)和水平触发(LT)**模式。
  • 不会遍历所有文件描述符,而是通过事件通知的方式,只处理实际发生变化的描述符,适合高并发服务器。
  • epoll 在注册文件描述符后,只需调用一次添加操作,后续的事件管理更高效。
  • 优势
    • 事件驱动模型:epoll 基于事件驱动,不再像 selectpoll 那样需要线性扫描所有描述符。只有发生注册事件时 epoll 才会通知应用程序。
    • 水平触发(LT, Level Triggered):是默认方式,类似于 select / poll 的工作方式,只要文件描述符上有未处理的数据,每次调用 epoll_wait 都会返回该文件描述符。
    • 边缘触发(ET, Edge Triggered):仅在状态发生变化时通知一次,需要用户在事件发生时读取所有数据,否则可能会错过后续事件。减少了重复事件通知的次数,但增加了编程的复杂度,通常需要结合非阻塞 I/O 使用。
    • 内存映射:epoll 通过内存映射(mmap)减少了在内核和用户空间之间的数据复制,进一步提高了性能。

3. 为什么网络 I/O 会被阻塞?

  • 网络 I/O 会被阻塞是因为在进行网络数据传输时,操作系统在等待数据的发送或接收完成之前,会将进程挂起,直到数据传输完成后才恢复进程执行。

阻塞的主要原因

  • 等待数据到达或发送完成:当进程尝试从网络套接字中读取数据时,如果数据尚未到达,操作系统会使进程进入阻塞状态,直到数据到达为止。同样,当数据未能立即发送出去时,发送操作也可能被阻塞,等待缓冲区有空闲空间。
  • 系统资源有限:当系统资源(如网络缓冲区、连接数等)被占满时,进一步的 I/O 请求可能会被阻塞,等待资源释放后才能继续。
  • 默认的阻塞行为:大多数网络API(如 recvsendaccept 等)在默认情况下都是阻塞的,即调用这些 API 时,如果条件不满足,会使调用者等待,直到 I/O 操作完成。

常见连接阻塞

  • accept() 阻塞
    • 服务器在调用 accept() 时,会阻塞在这个调用上,直到有新的客户端连接请求到来。
    • 此时,服务器进程会等待客户端的连接,无法继续执行其他操作。
  • connect() 阻塞
    • 客户端在调用 connect() 尝试连接服务器时,如果连接不能立即建立(如服务器响应慢或网络不通畅),connect() 会阻塞,直到连接成功或超时。

常见的数据传输阻塞

  • resv()read() 阻塞
    • 当使用这些函数从套接字中读取数据时,如果缓冲区中没有数据(如对方尚未发送数据),进程会被阻塞,直到数据到达。
  • send()write() 阻塞
    • 当缓冲区已满(如网络拥塞或对方接受缓慢),数据无法写入时,send()write() 会阻塞,等待缓冲区有空闲时间时再发送数据。


原文地址:https://blog.csdn.net/Again_acme/article/details/145182340

免责声明:本站文章内容转载自网络资源,如侵犯了原著者的合法权益,可联系本站删除。更多内容请关注自学内容网(zxcms.com)!