unix下的I/O------阻塞,非阻塞,同步,异步

系统 其他OS
前4种模型的主要区别在于第一阶段,因为它们的第二阶段都是一样的:在数据从内核缓冲区拷贝到进程缓冲区期间,进程阻塞与recvfrom这个系统调用中。

参考 Richard Stevens的“UNIX® Network Programming Volume 1, Third Edition: The Sockets Networking”。

Stevens一共提出了五种 IO Model:

  • blocking IO
  • nonblocking IO
  • IO multiplexing (select and poll)
  • signal driven IO (SIGIO)
  • asynchronous IO (the POSIX aio_functions)

先说一下IO发生时所涉及的对象和步骤。

一个输入操作通常包括下面两个阶段:

  1. 等待数据准备好 (Waiting for the data to be ready)。对于一个套接口上的输入操作,通常涉及等待数据从网络到达,到达后它被拷贝到内核的某个缓冲区。
  2. 将数据从内核缓存区拷贝到进程缓冲区中 (Copying the data from the kernel to the process)

记住这两个阶段很重要,因为以下要讨论的五种IO Model的区别就是在两个阶段上各有不同的情况。

Blocking I/O Model(阻塞I/O)

默认情况下所有的套接口都是blocking。

进程调用recvfrom,其系统调用直到数据报到达(第一阶段)且被拷贝到应用进程的缓冲区中(第二阶段)或者发生错误(最常见的错误是系统调用被信号中断)才返回。进程在从调用recvfrom开始到它返回的整个过程是被阻塞的。 recvfrom成功返回后,应用进程开始处理数据报。

Nonblocking I/O Model(非阻塞I/O)

前三次调用recvfrom时数据还没准备好,这是内核立即返回一个EWOULDBLOCK错误。第四次调用recvfrom时数据已准备好,它被拷贝到应用进程缓冲区,recvfrom接着成功返回,然后应用进程开始处理数据报。

这里最关键的一个操作就是轮询(polling)。应用进程持续轮询内核,以查看数据是否就绪。这样做往往会耗费大量的CPU时间,这种模型通常会在专门提供某种功能的系统才有。

I/O Multiplexing Model(I/O复用模型)

当用户进程调用了select,那么整个进程会被block,而同时,kernel会“监视”所有select负责的socket,当任何一个socket中的数据准备好了,select就会返回套接字可读这个条件,我们调用recvfrom把所读数据报拷贝到应用程序进程缓冲区。

和blocking IO的图比较,I/O复用并没有显示出什么优势。事实上,可能稍有劣势。因为这里需要使用两个system call (select 和 recvfrom),而blocking IO只调用了一个system call。但是,用select的优势在于它可以同时处理多个connection。

Signal-Driven I/O Model(信号驱动I/O模型)

我们首先开启套接口的信号驱动I/O功能,并通过sigaction系统调用安装一个信号处理函数。该系统调用将立即返回,我们的进程这是并没有被阻塞,而是继续执行。当数据报准备好读取时,内核就为该进程产生一个SIGIO信号。我们随后既可以在信号处理函数中调用recvfrom读取数据报,并通知主循环数据已准备好待处理,也可以立即通知主循环,让它来读取数据报。无论如何处理SIGIO信号,这种模型的优势在于等待数据报到达(第一阶段)期间,进程可以继续执行,不被阻塞。

Asynchronous I/O Model(异步I/O模型)

进程发起read操作之后,立刻就可以开始去做其它的事。而另一方面,从kernel的角度,当它受到一个asynchronous read之后,首先它会立刻返回,所以不会对用户进程产生任何block。然后,kernel会等待数据准备完成,然后将数据拷贝到用户内存,当这一切都完成之后,kernel会给用户进程发送一个signal,告诉它read操作完成了。

这个模型工作机制是:告诉内核启动某个操作,并让内核在整个操作(包括第二阶段,即将数据从内核拷贝到进程缓冲区中)完成后通知我们。

这种模型和前一种模型区别在于:信号驱动I/O是由内核通知我们何时可以启动一个I/O操作,而异步I/O模型是由内核通知我们I/O操作何时完成。

五种I/O模型介绍完了,下面来说说blocking和non-blocking的区别在哪,synchronous IO和asynchronous IO的区别在哪。

blocking I/Ovs non-blocking I/O :调用blocking IO会一直block住对应的进程直到操作完成,而non-blocking IO在kernel还准备数据的情况下会立刻返回。

synchronous I/O vs asynchronous I/O:

先看看这两个定义:

A synchronous I/O operation causes the requesting process to be blocked until that I/O operation completes;

An asynchronous I/O operation does not cause the requesting process to be blocked;

两者的区别就在于synchronous IO做”IO operation”的时候会将process阻塞。按照这个定义,之前所述前四种模型blocking I/O,non-blocking I/O,IO multiplexing,signal driven IO都属于synchronous IO。有人可能会说,non-blocking IO并没有被block啊。这里有个非常“狡猾”的地方,定义中所指的”IO operation”是指真实的IO操作,就是例子中的recvfrom这个system call。non-blocking IO在执行recvfrom这个system call的时候,如果kernel的数据没有准备好,这时候不会block进程。但是,当kernel中数据准备好的时候,recvfrom会将数据从 kernel拷贝到用户内存中,这个时候(第二阶段)进程是被block了,在这段时间内,进程是被block的。而asynchronous IO则不一样,当进程发起IO 操作之后,就直接返回再也不理睬了,直到kernel发送一个信号,告诉进程说IO完成。在这整个过程中,进程完全没有被block。

各个IO Model的比较如图所示:

前4种模型的主要区别在于第一阶段,因为它们的第二阶段都是一样的:在数据从内核缓冲区拷贝到进程缓冲区期间,进程阻塞与recvfrom这个系统调用中。

责任编辑:艾婧 来源: welbeckxu的博客
相关推荐

2018-03-28 08:52:53

阻塞非阻塞I

2019-07-23 11:01:57

Python同步异步

2012-10-10 10:00:27

同步异步开发Java

2015-07-03 10:12:04

编程同步非阻塞

2023-07-31 08:55:01

Java NIO非阻塞阻塞

2021-06-04 18:14:15

阻塞非阻塞tcp

2021-03-04 08:34:55

同步阻塞非阻塞

2021-10-13 06:49:15

网络 IO

2022-06-22 08:16:29

异步非阻塞框架

2021-02-27 16:08:17

Java异步非阻塞

2023-12-06 07:28:47

阻塞IO异步IO

2019-05-05 08:50:42

阻塞非阻塞BIO

2016-11-28 09:08:43

java系统异步非阻塞

2017-03-01 16:40:12

Linux驱动技术设备阻塞

2021-01-10 11:21:33

JavaScript语言开发

2022-09-22 10:51:32

服务端开发者异步非阻塞编程

2023-03-15 08:39:07

远程服务调用

2016-11-04 12:51:46

Unix网络IO 模型

2011-12-07 17:17:02

JavaNIO

2010-03-16 19:08:03

Java线程同步
点赞
收藏

51CTO技术栈公众号