BIO、NIO、AIO

190 阅读4分钟

小知识,大挑战!本文正在参与“程序员必备小知识”创作活动。

BIO、NIO、AIO 介绍

  • 阻塞 IO

    • 通讯需要 TCP 发送缓冲区和 TCP 接收缓冲区。
    • 发送方 A 发送数据到 TCP 发送缓冲区,TCP 发送缓冲区再把消息发送出去,经过网络传递后,消息会发送到接收方 B 的 TCP 接收缓冲区中。
    • 接收方 B 去 TCP 接收缓冲区接收数据,如果数据不存在,就是让接收方 B 一直等着,直到有数据再把数据交给接收方 。
    • 在接收到数据之前,接收方 B 一直是阻塞状态的。
  • 非阻塞 IO

    • 同样是上面的例子,当接收方 B 去 TCP 接收缓冲区接收数据时,如果数据不存在,TCP 接收缓冲区会返回一个错误码,告诉接收方 B 不要再等待了。
    • 这期间,接收方 B 是不会阻塞住的。
  • IO 复用模型

    • 思想
      • Linux 系统把所有网络请求以一个 fd(文件描述符)来标识,让一个线程监控多个网络请求。这样就可以只需要一个或几个线程就可以完成数据状态询问的操作,当有数据准备就绪之后再分配对应的线程去读取数据,这么做就可以节省大量的线程资源。
    • 函数
      • select 函数
      • poll 函数
      • epoll 函数
    • 优点
      • 解决了一个线程可以监控多个 fd 的问题
  • 信号驱动 IO 模型

    • 思想
      • 复用 IO 模型解决了一个线程可以监控多个 fd 的问题,但是 select 是采用轮询的方式来监控多个 fd 的,通过不断的轮询 fd 的可读状态来知道是否有可读的数据,而无脑的轮询就显得有点暴力,因为大部分情况下的轮询都是无效的,所以有人就想,能不能不要我总是去问你是否数据准备就绪,能不能我发出请求后等你数据准备好了就通知我,所以就衍生了信号驱动 IO 模型。
    • 实现
      • 执行一个信号处理函数,此时请求立刻返回,当数据准备就绪后,就生成对应进程 SIGIO 信号,通过信号回调通知应用线程调用接口读取数据。
  • 异步 IO

    • 思想
      • 无论是 IO 复用还是信号驱动,我们要读取一个数据总是要发起两阶段的请求,第一次发送 select 请求,询问数据状态是否准备好,第二次发送 recevfrom 请求读取数据。
      • 我们想能不能有一种一劳永逸的方式,我只要发送一个请求,告诉内核我要读取数据,然后我就什么都不管了,然后内核去帮我完成剩下所有的事情?
    • 实现
      • 应用告知内核启动某种操作,并让内核在整个操作完成之后,通知应用。
      • 这个模型与信号驱动模型的主要区别在于,信号驱动 IO 只是由内核通知我们何时可以开始下一个 IO 操作,而异步 IO 模型是由内核通知我们操作什么时候完成。
  • 同步请求和异步请求

    • 在 IO 模型里面如果请求方从发起请求到数据最后完成的这一段过程中都需要自己参与,那么这种请求我们称为同步请求;反之,如果应用发送完执行后就不参与过程了,只需要等待最终完成结果的通知,那么这就属于异步。
  • 同步阻塞、同步非阻塞、异步阻塞

    • 同步阻塞和同步非阻塞:
      • 不同点:发起读取请求的时候一个请求阻塞,一个请求不阻塞。
      • 相同点:他们都需要应用自己监控整个数据完成的过程;
    • 异步非阻塞:
      • 没有异步阻塞,因为异步模型下,发送完就立即返回了,没有后续流程了,所以它不会阻塞。

参考文档:

100%弄明白5种IO模型