同步、异步、阻塞、非阻塞与5种I/O模型

一、概念
1.同步与异步
同步(synchronous )和异步(asynchronous)关注的是消息通信机制 ,主体是内核。

同步:在发出一个调用后,没得到结果之前,该调用就不返回。但是一旦调用返回,就得到返回值了。换句话说,就是由调用者主动等待这个调用的结果。
异步:调用在发出之后,这个调用就直接返回了,所以没有返回结果。换句话说,当一个异步过程调用发出后,调用者不会立刻得到结果。而是在调用发出后,被调用者通过状态、通知来通知调用者,或通过回调函数处理这个调用。典型的异步编程模型比如Node.js。

举个通俗的例子:你打电话问书店老板有没有《分布式系统》这本书,如果是同步通信机制,书店老板会说,你稍等,”我查一下",然后开始查啊查,等查好了(可能是5秒,也可能是一天)告诉你结果(返回结果)。而异步通信机制,书店老板直接告诉你我查一下啊,查好了打电话给你,然后直接挂电话了(不返回结果)。然后查好了,他会主动打电话给你。在这里老板通过“回电”这种方式来回调。

同步与非同步,讨论的是程序调用的结果如何传递给程序,主体是内核调用等到有结果了再返回同步调用先马上答应一声返回没结果的信息,再等到有结果的时候再通过各种方法通知程序有结果了的是异步
异步是编程语言和调用的API协同模拟出来的一种程序控制流风格,编程语言和API不支持的话,无法使用这种风格。这里的关键点是这可以和OS无关:OS即使没有异步系统调用,编程语言也可以模拟一个出来;即使OS有异步系统调用,编程语言也可以屏蔽这个能力

2.阻塞与非阻塞
阻塞和非阻塞关注的是程序在等待调用结果(消息,返回值)时的状态,主体是程序。

阻塞:调用结果返回之前,当前线程会被挂起。调用线程只有在得到结果之后才会返回。
非阻塞:不能立刻得到调用结果之前,该调用不会阻塞当前线程。

还是上面的例子,你打电话问书店老板有没有《分布式系统》这本书,你如果是阻塞式调用,你会一直把自己“挂起”,直到得到这本书有没有的结果,如果是非阻塞式调用,你不管老板有没有告诉你,你自己先一边去玩了, 当然你也要偶尔过几分钟check一下老板有没有返回结果。在这里阻塞与非阻塞与是否同步异步无关。跟老板通过什么方式回答你结果无关。
阻塞与非阻塞,讨论的是程序在等待调用时是怎么样的,主体是程序不干正事傻等的是阻塞干其他事情,是不是看看好了没的是非阻塞
非阻塞系统调用是个“伪概念”。换句话说,没有非阻塞的系统调用。只有返回特别快的阻塞系统调用和返回时间不确定的阻塞系统调用。

二、5种I/O模型
《UNIX网络编程:卷一》第六章:I/O复用向我们提及了5种类UNIX下可用的I/O模型:
阻塞式I/O;
非阻塞式I/O;
I/O复用(select,poll,epoll…);
信号驱动式I/O(SIGIO);
异步I/O(POSIX的aio_系列函数);

默认情况下,所有套接字都是阻塞的。首先理解这么个流程,一个输入操作通常包括两个不同阶段:
(1)等待数据准备好;
(2)从内核向进程复制数据。

以下是图解:
阻塞式I/O模型:对于一个套接字上的输入操作,第一步通常涉及等待数据从网络中到达。当所有等待分组到达时,它被复制到内核中的某个缓冲区。第二步就是把数据从内核缓冲区复制到应用程序缓冲区。 好,下面我们以阻塞套接字的recvfrom的的调用图来说明阻塞在这里插入图片描述标红的这部分过程就是阻塞,直到阻塞结束recvfrom才能返回。

非阻塞式I/O: 以下这句话很重要:进程把一个套接字设置成非阻塞是在通知内核,当所请求的I/O操作非得把本进程投入睡眠才能完成时,不要把进程投入睡眠,而是返回一个错误。看看非阻塞的套接字的recvfrom操作如何进行
在这里插入图片描述
可以看出recvfrom总是立即返回。

I/O多路复用:虽然I/O多路复用的函数也是阻塞的,但是其与以上两种还是有不同的,I/O多路复用是阻塞在select,epoll这样的系统调用之上,而没有阻塞在真正的I/O系统调用如recvfrom之上。如图
在这里插入图片描述

信号驱动式I/O:用的很少,就不做讲解了。直接上图
在这里插入图片描述
异步I/O:这类函数的工作机制是告知内核启动某个操作,并让内核在整个操作(包括将数据从内核拷贝到用户空间)完成后通知我们。如图:
在这里插入图片描述
注意红线标记处说明在调用时就可以立马返回,等函数操作完成会通知我们。

等等,大家一定要问了,同步这个概念你怎么没涉及啊?别急,您先看总结。 其实前四种I/O模型都是同步I/O操作,他们的区别在于第一阶段,而他们的第二阶段是一样的:在数据从内核复制到应用缓冲区期间(用户空间),进程阻塞于recvfrom调用。相反,异步I/O模型在这两个阶段都要处理。

在这里插入图片描述
再看POSIX对这两个术语的定义:
同步I/O操作:导致请求进程阻塞,直到I/O操作完成;
异步I/O操作:不导致请求进程阻塞。

好,下面我用我的语言来总结一下阻塞,非阻塞,同步,异步

阻塞,非阻塞:进程/线程要访问的数据是否就绪,进程/线程是否需要等待;

同步,异步:访问数据的方式,同步需要主动读写数据,在读写数据的过程中还是会阻塞异步只需要I/O操作完成的通知,并不主动读写数据,由操作系统内核完成数据的读写。

小结:
一个IO操作(调用)其实分成了两个步骤:1.程序发起IO请求,2.实际的IO操作。阻塞IO和非阻塞IO的区别在于第一步,程序发起IO请求是否会被阻塞,如果阻塞直到完成那么就是传统的阻塞IO;如果程序不阻塞,那么就是非阻塞IO。
同步IO和异步IO的区别就在于第二个步骤是否阻塞。如果实际的IO读写阻塞请求进程,那么就是同步IO,因此阻塞IO、非阻塞IO、IO复用、信号驱动IO都是同步IO;如果不阻塞,而是操作系统帮你做完IO操作再将结果返回给你,那么就是异步IO。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值