I/O模型

Richard Stevens在UNIX Network Programming中讲述了五种I/O模型

  • Blocking IO
  • Nonblocking IO
  • IO multiplexing
  • Signal driven IO
  • Asynchronous IO

而本文也是基于这五种I/O模型,以及交叉着同步与异步&阻塞与非阻塞的概念。但在探讨I/O模型之前,先要了解一下I/O模型发生的对象和步骤。 对于一个文件I/O的操作(这里以read为例子),会涉及到两个对象:

  • 一个是调用这个I/O的进程process
  • 另外一个就是系统内核kernel

当一个read操作发生时,会经历两个阶段

  • 进程等待内核数据准备(Waiting for the data to be ready)
  • 将数据从内核拷贝到进程中 (Copying the data from the kernel to the process)

Blocking IO(阻塞IO)

在默认情况下,所有的IO操作都是Blocking io,流程如上图所示,步骤为:

  1. 应用进程(application process) 调用了recvfrom这个系统调用
  2. 然后内核(kernel)开始了IO的第一个阶段:准备数据。在内核准备数据期间,应用进程是一直阻塞的。(Waiting for the data to be ready)
  3. 内核准备好数据之后,把数据从内核copy到应用内存。在内核copy数据期间,应用进程依然是一直阻塞的。(Copying the data from the kernel to the process)
  4. 内核返回结果,应用进程才解除block的状态,重新继续执行

Blocking IO的特点就是在IO执行的两个阶段都阻塞了,而Blocking IO整个过程也是同步模型,所以Blocking IO可以叫做同步阻塞IO

non-blocking IO(非阻塞IO)

Non-blocking IOBlocking IO不同点在于不断的查询数据是否准备好,如上图所示,流程为:

  1. 应用进程(application process) 调用了recvfrom这个系统调用
  2. 内核告诉应用进程,数据还没有准备好
  3. 应用进程发现数据没有准备好,不停的调用recvfrom这个系统调用,内核在数据没有准备好的情况下不停的告诉应用进程数据没有准备好。
  4. 内核准备数据。这个过程中,应用进程没有阻塞,因为它在不停的调用!(Waiting for the data to be ready)
  5. 在应用进程不停的调用中,恰好这次内核把数据准备好了,然后内核把数据copy到应用进程内存。在内核copy数据期间,应用进程是一直阻塞的。(Copying the data from the kernel to the process)
  6. 内核返回结果,应用进程解除block的状态,重新继续执行

Non-Blocking IO模型中,数据准备阶段并没有阻塞,因为应用进程不断的查询内核数据是否准备完毕,并没有被阻塞,实际上应用进程可以在这时干其他事情。在数据复制阶段阻塞。 Non-blocking IO模型就不能理解为同步非阻塞模式了,但是也不能理解为异步非阻塞模式,算是同步和异步的一个混合体。

IO multiplexing(多路复用)

  1. 应用进程(application process) 调用了select这个系统调用
  2. 内核开始准备数据。在内核准备数据期间,应用进程是一直阻塞的。(Waiting for the data to be ready)
  3. 内核告诉应用进程数据准备好了
  4. 应用进程(application process) 调用了recvfrom这个系统调用
  5. 内核把数据copy到应用进程内存。在内核copy数据期间,应用进程是一直阻塞的。(Copying the data from the kernel to the process)
  6. 内核返回结果,应用进程解除block的状态,重新继续执行

优缺点

  • 当用户进程调用了select,内核监视这个IO请求
  • 当N个用户进程调用了select,内核监视NIO请求
  • 有一个用户进程的IO数据准备好了,内核告诉该用户进程数据准备好了,来取吧
  • 所以优点就在于内核可以多监视更多的IO请求,可以同时处理多个connection(多说一句。所以,如果处理的连接数不是很高的话,使用select/epollweb server不一定比使用multi-threading + blocking IOweb server性能更好,可能延迟还更大。select/epoll的优势并不是对于单个连接能处理得更快,而是在于能处理更多的连接。)
  • IO multiplexing Model中,如上图所示,整个用户的process其实是一直被block的,只不过process是被select这个函数block,而不是被socket IO请求给block。这句很重要。
  • 实际中,对于每一个socket,一般都设置成为non-blocking,轮训的时机设计好,才能体现出该IO设计模型的优势。

Signal driven I/O(信号IO)

  1. 应用进程发起一个信号,告诉内核说我需要什么文件,然后立马返回
  2. 内核准备数据。应用进程该干嘛干嘛,不会阻塞。
  3. 内核准备好数据,告诉应用进程来取数据
  4. 应用进程请求取数据
  5. 内核把数据复制到应用进程。应用进程阻塞。
  6. 返回数据

Asynchronous I/O(异步非阻塞)

  • 应用进程发起一个信号,告诉内核说我需要什么文件,然后立马返回
  • 内核准备数据。应用进程该干嘛干嘛,不会阻塞。
  • 内核把数据copy到应用进程内存。应用进程该干嘛干嘛,不会阻塞。
  • 返回数据

总结

  • Blocking I/O,数据准备、数据copy全阻塞,同步阻塞IO
  • Non-blocking I/O,数据准备不阻塞,数据copy阻塞,非阻塞IO
  • I/O multiplexing,数据准备阻塞,数据copy阻塞,多路复用IO,优点可以支持更多IO请求
  • Signal driven I/O (SIGIO),数据准备不阻塞,数据copy阻塞,异步阻塞IO
  • Asynchronous I/O,数据准备、数据copy 全部阻塞。异步非阻塞IO