【Linux】Linux/Unix五种I/O模型

11

Linux/Unix五种I/O模型


阻塞-blocking

  • 调用者调用了某个函数,然后等待这个函数返回,在这期间什么都不做不停的去检查这个函数有没有返回,应用程序必须等这个函数返回才能进行下一步的动作。
    • 即,针对阻塞I/O执行的系统调用可能因为无法立即完成而被操作系统挂起,直到等待的时间发生为止,才可以继续执行下一步的操作。
  • 可能被阻塞的系统调用包括accept、send、recv、connect。

image-20221016174226613


非阻塞-non blocking (NIO)

  • 非阻塞I/O执行系统调用总是立即返回,不管事件是否已经发生,若事件没有发生,则返回-1,此时可以根据errno区分这两种情况,对于accept、recv和send、事件未发生时,errno通常被设置成EAGAIN
  • 我们只有在事件已经发生的情况下操作非阻塞I/O,才能提高程序的效率。因此,非阻塞I/O通常要和其它I/O通知机制一起使用,比如I/O多路复用和SIGIO信号。

image-20221016182143323


I/O复用-IO multiplexing

  • I/O多路复用是最常用的I/O通知机制
  • 它指的是: 应用程序通过I/O复用函数向内核注册一组事件,内核通过I/O复用函数把其中就绪的事件通知给应用程序
  • 在单进程/线程的情况下,可以检测多个客户的事件是否发生。
  • I/O复用函数本身也是阻塞的,它们能提高程序效率的原因在于它们可以同时监听多个I/O事件
  • 单单使用I/O多路复用并不能处理高并发,而要处理高并发还是需要结合多进程/线程。

image-20221016184606349


信号驱动-signal driven

  • 为某一进程安装一个信号处理函数,进程运行,当I/O事件就绪,该进程收到SIGIO信号,然后开始处理I/O事件。
    • 我们可以为目标文件描述符指定宿主进程,被指定的宿主进程将捕获到SIGIO信号,当目标问文件名描述符上有事件发生时,SIGIO信号的信号处理函数将被触发,我们可在该信号处理函数中对目标文件描述符执行非阻塞I/O操作

image-20221016185112070

  • 内核在第一个阶段是异步,在第二个阶段是同步;信号驱动I/O与非阻塞I/O的区别在于它提供了消息通知机制,不需要用户进程不断的轮询检查,减少了系统调用的次数,提高了效率。

  • 补充:
    • 同步与异步: 同步是执行或调用一个方法时,每次都需要拿到对应的结果才会继续往后执行;异步与同步相反,它会在执行或调用一个方法后就继续往后执行,不会等待获取执行结果。二者的区别就是处理请求发出后,是否需要等待请求结果,再去继续执行其他操作。——来源线程与同步异步

异步I/O-asynchronous

  • 从理论上来讲,阻塞I/O、I/O复用和信号驱动I/O都是同步I/O模型,因为在这三种I/O模型中,I/O的读写操作,都是在I/O事件发生之后,由应用程序来完成的。

  • 对异步I/O而言,用户可以直接对I/O执行读写操作,这些操作告诉内核用户读写缓冲区的位置,以及I/O操作完成之后内核通知应用程序的方式。(POSIX规范)
    • 在Linux中,每次调用aio_read函数告诉内核描数字缓冲区指针和缓冲区的大小、文件偏移及通知的方式,然后立即返回,当内核将数据拷贝到缓冲区后,再通知应用程序。
  • 异步I/O的读写操作总是立即返回,无论I/O是否阻塞,因为真正的读写操作已由内核接管

  • 对比:
    • 同步I/O模型要求用户代码自行执行I/O操作(将数据从用户缓冲区拷贝到内核缓冲区,从内核缓冲区拷贝到用户缓冲区)。
    • 异步I/O则是由内核来执行I/O操作(即数据在用户缓冲区域内核缓冲区的移动是由内核在"后台"完成的)。
  • 可以这样理解:
    • 同步I/O向应用程序通知的是I/O就绪事件
    • 异步I/O向应用程序通知的是I/O完成事件

image-20221016185547160