IO模型对比:同步、异步、阻塞、非阻塞

最近工作接触到了网络服务同步和异步,所以学习了下《UNIX网络编程》,在此作下总结。

一、I/O模型

输入/输出(I/O)是在主存和外部设备(如磁盘驱动器、终端和网络)之间拷贝数据的过程。输入是从I/O设备拷贝数据到主存,而输出是从主存拷贝数据到I/O设备。比如,网络可视为一个I/O设备,作为数据源和数据接收方。系统可以经过网络读取其他机器发送来的数据,并将数据复制到自己主存中。 

下面分别介绍Unix的5种I/O模型:

  • 阻塞式IO
  • 非阻塞IO
  • IO复用
  • 信号驱动IO
  • 异步IO

一个输入操作通常为以下两个阶段:

(1)等待数据准备好;

(2)从内核复制数据到进程;

拿网络中客户端请求服务的例子说明五种模型。

在网络请求中,套接字(socket)是实现通信的一个端点,应用程序可以通过它发送或接收数据,可对其进行像对文件一样的打开、读写和关闭等操作。

对于一个soket上的输入操作:

(1)等待数据从网络中到达。数据到达时被复制到内核中的缓冲区;

(2)把数据从内核缓冲区复制到应用进程缓冲区。

1. 阻塞式IO模型

阻塞式IO模型是最常用的,我们将recvfrom作为系统调用,来观察应用进程和内核之间的区别。下图中进程调用recvfrom,该系统调用直到数据报准备好且拷贝到应用缓冲区或者出错才返回,也就是说在数据返回之前,进程被阻塞,当进程返回成功指示后,才可以开始下面的处理。

2. 非阻塞式IO模型

下图中,前三次调用recvfrom,数据还没准备好,内核会立即返回一个EWOULDBLOCK错误,直到第四次调用时,数据准备好被拷贝到应用缓冲区,该系统调用返回成功指示,接下来开始处理数据。当应用进程像这样对一个非阻塞描述字循环调用recvfrom时,这实际上就是轮询(polling)。

应用程序不断地查询内核,检查数据是否准备好,这对CPU来说是一种浪费,所以这种模型比较少见。

3. IO复用模型

IO复用是指通过调用select,poll或者epoll函数,监听多个socket连接,每新来一个socket连接,就会被加入到监听列表,实现单个线程同时处理多个网络连接的IO。基本原理是通过select,poll或epoll不断轮询负责的全部socket,当其中一个数据准备好,就通知进程。然后调用recvfrom拷贝数据从内核到进程,返回成功指示后,进行下一步处理。

应用进程虽然不会被socket的IO阻塞,但一直被select,poll或epoll阻塞。如果socket数不是很多的话,使用IO复用模型可能比多线程 + 阻塞IO延迟更大,因为IO复用模型相对比之前的模型需要两次系统调用,它的优势在于能处理较多的连接。

4. 信号驱动IO模型

该模型通过系统调用sigaction安装一个信号处理程序。当内核准备好数据后,发送信号告知进程。在信号处理程序中调用recvfrom读取数据,并通知主循环。这种模型的好处是当等待数据报到达时,IO不被阻塞。主循环可以继续执行,只是等待信号处理程序的通知:数据已准备好被读。

5. 异步IO模型

异步IO模型让内核完成整个操作(包括将数据从内核拷贝到进程缓冲区)后才进行通知应用进程。这个模型和信号驱动模型的主要区别在于:信号驱动IO是由内核通知我们何时可以启动一个IO操作,而异步IO是由内核通知我们IO操作何时完成。

下图中调用aio_read,传递内核描述字、缓冲区指针、缓冲区大小、文件偏移,并告诉内核整个操作完成时如何通知我们。该系统调用立即返回,不阻塞于IO操作。该图中,内核在操作完成后传递一个信号,该信号直到数据被拷贝到缓冲区才产生,这是和信号驱动IO的不同之处。

二、IO模型区别

1. 对比

从这两个阶段来看,前四种模型在第一阶段有所不同,但第二个阶段基本相同,把数据从内核拷贝到应用进程的缓冲区时,进程被阻塞于recvfrom调用。异步IO模型的两个阶段都不同于前四种模型。

2. 同步vs异步

同步IO操作会阻塞请求进程,直到IO操作完成。

异步IO操作不会阻塞请求进程。

前四种模型:阻塞IO模型、非阻塞IO模型、IO复用模型和信号驱动IO都是同步IO模型,因为真正的IO操作(recvfrom)阻塞进程。

猜你喜欢

转载自www.cnblogs.com/hithink/p/11503792.html