Linux中I/O模型 —— 阻塞非阻塞和同步异步|8月更文挑战

114 阅读3分钟

这是我参与8月更文挑战的第6天,活动详情查看:8月更文挑战

Linux/Unix常见IO模型:阻塞(Blocking I/O)非阻塞(Non-Blocking I/O)IO多路复用(I/O Multiplexing)信号驱动 I/O(Signal Driven I/O) (不常用)和异步(Asynchronous I/O) 。网络IO操作主要涉及到内核进程,其主要分为两个过程:

  • 内核等待数据可操作(可读或可写)——阻塞与非阻塞
  • 内核与进程之间数据的拷贝——同步与异步

1 基础概念

① 阻塞(Blocking)和非阻塞(Non-blocking)

阻塞和非阻塞发生在内核等待数据可操作(可读或可写)时,指做事时是否需要等待应答。

  • 阻塞: 内核检查数据不可操作,则不立即返回
  • 非阻塞: 内核检查数据不可操作,则立即返回

② 同步(Synchronous)和异步(Asynchronous)

同步和异步发生在内核与进程交互时,进程触发IO操作后是否需要等待或轮询查看结果。

  • 同步: 触发IO操作 → 等待或轮询查看结果
  • 异步: 触发IO操作 → 直接返回去做其它事,IO处理完后内核主动通知进程

2 阻塞I/O

当用户程序执行 read ,线程会被阻塞,一直等到内核数据准备好,并把数据从内核缓冲区拷贝到应用程序的缓冲区中,当拷贝过程完成,read 才会返回。阻塞等待的是 内核数据准备好数据从内核态拷贝到用户态 两个过程。过程如下图:

阻塞IO.png

3 非阻塞I/O

非阻塞的 read 请求在数据未准备好的情况下立即返回,可以继续往下执行,此时应用程序不断轮询内核,直到数据准备好,内核将数据拷贝到应用程序缓冲区,read 调用才可以获取到结果。过程如下图:

非阻塞IO.png

注意,这里最后一次 read 调用,获取数据的过程,是一个同步的过程,是需要等待的过程。这里的同步指的是内核态的数据拷贝到用户程序的缓存区这个过程。

4 同步I/O

无论 readsend阻塞I/O,还是 非阻塞I/O 都是同步调用。因为在 read 调用时,内核将数据从内核空间拷贝到用户空间的过程都是需要等待的,即这个过程是同步的,如果内核实现的拷贝效率不高,read 调用就会在这个同步过程中等待比较长的时间。

5 异步I/O

真正的异步 I/O 是内核数据准备好数据从内核态拷贝到用户态 这两个过程都不用等待。

当我们发起 aio_read (异步 I/O) 之后,就立即返回,内核自动将数据从内核空间拷贝到用户空间,这个拷贝过程同样是异步的,内核自动完成的,和前面的同步操作不一样,应用程序并不需要主动发起拷贝动作。过程如下图:

异步IO.png