一、提出问题
在聊到linux的五种io模型的时候,包括阻塞io,非阻塞io,io多路复用,信号驱动io,异步io等。那具体同步和异步是怎么区分,同步跟阻塞有什么区别。找一下资料系统地学习一下。我才不会说面试被问到了。
先说一下网络变成的I/O模型。5种网络模型基本问了人或者查一下资料都有。但里面提到的阻塞、非阻塞,同步、异步这几个概念的区别就傻傻分不清楚。
二、现存观点
在网上查了几个资料
说法一:(https://www.jianshu.com/p/aed6067eeac9)
同步异步的概念是从消息的通知机制来区别
阻塞非阻塞主要是程序(线程)等待消息通知的状态来区别
说法二:https://www.zhihu.com/question/19732473/answer/241673170
在进程通信层面, 阻塞/非阻塞, 同步/异步基本是同义词, 但是需要注意区分讨论的对象是发送方还是接收方。
三、资料论证
(一)五种I/O模型
查一下《UNIX网络编程:卷一》第六站--I/O复用。
书中说道了5种UNIX下可用的I/O模型:
阻塞式I/O
非阻塞式I/O
I/O复用(select,poll,epoll)
信号驱动式(SIGIO)
异步I/O(POSIX的aio_系列函数)
先理解这么个流程,一个输入操作通常包括两个不同阶段:
(1)等待数据准备好;
(2)从内核向进程复制数据。
阻塞式I/O模型:默认情况下,所有套接字都是阻塞的
对于一个套接字上的输入操作,第一步通常涉及等待数据从网络中到达。当所有等待分组到达时,它被复制到内核中的某个缓冲区。第二步就是把数据从内核缓冲区复制到应用程序缓冲区。好,下面我们以阻塞套接字的recvfrom的的调用图来说明阻塞
用户进程会阻塞于第一第二阶段
非阻塞式I/O:以下这句话很重要:进程把一个套接字设置成非阻塞是在通知内核,当所请求的I/O操作非得把本进程投入睡眠才能完成时,不要把进程投入睡眠,而是返回一个错误。看看非阻塞的套接字的recvfrom操作如何进行
第一阶段用户进程调用会立即返回,但返回的是是不完整的结果, 还可以是一个空值
第二阶段则使用户进程阻塞
I/O多路复用:虽然I/O多路复用的函数也是阻塞的,但是其与以上两种还是有不同的,I/O多路复用是阻塞在select,epoll这样的系统调用之上,而没有阻塞在真正的I/O系统调用如recvfrom之上。如图
信号驱动式I/O:用的很少,就不做讲解了。直接上图
异步I/O:这类函数的工作机制是告知内核启动某个操作,并让内核在整个操作(包括将数据从内核拷贝到用户空间)完成后通知我们。如图:
(二)五种I/O模型的对比
前4中模型的主要区别在于第一阶段,因为他们的第二阶段都是一样的:在数据从内核复制到调用者的缓冲区期间,金车鞥阻塞于recvfrom调用。相反,异步I/O模型在这两个阶段则没有发生阻塞。
(三)同步I/O与异步I/O定义
POSIX把这两个术语定义为:
同步I/O操作:导致请求进程阻塞,直到I/O操作完成
异步I/O操作:不导致请求进程阻塞
根据上述定义,前4中模型--阻塞式I/O、非阻塞式I/O、I/O多路复用模型和信号驱动式I/O都是同步I/O模型,因为其中真正的I/O操作(recvfrom)将阻塞进程。只有异步I/O模型与POSIX定义的异步I/O相匹配。
四、总结
阻塞,非阻塞:进程/线程要访问的数据是否就绪,进程/线程是否需要等待;
同步,异步:访问数据的方式,同步需要主动读写数据,在读写数据的过程中还是会阻塞;异步只需要I/O操作完成的通知,并不主动读写数据,由操作系统内核完成数据的读写。