Linux IO - 同步,异步,阻塞,非阻塞


From:http://blog.csdn.net/historyasamirror/article/details/5778378

同步/异步,阻塞/非阻塞概念深度解析:http://blog.csdn.net/lengxiao1993/article/details/78154467


知乎上关于 阻塞和非阻塞、同步和异步 之间区别的生动解释。

https://www.zhihu.com/question/19732473

“阻塞”与"非阻塞"与"同步"与“异步"不能简单的从字面理解,提供一个从分布式系统角度的回答。


1.同步与异步

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

        同步和异步关注的是消息通信机制 (synchronous communication/ asynchronous communication)。

        所谓同步,就是在发出一个*调用*时,在没有得到结果之前,该*调用*就不返回。但是一旦调用返回,就得到返回值了。换句话说,就是由*调用者*主动等待这个*调用*的结果。

        而异步则是相反,*调用*在发出之后,这个调用就直接返回了,所以没有返回结果。换句话说,当一个异步过程调用发出后,调用者不会立刻得到结果。而是在*调用*发出后,*被调用者*通过状态、通知来通知调用者,或通过回调函数处理这个调用。

        典型的异步编程模型比如Node.js

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

        另一个例子来说明同步异步: 某业务需要甲乙甚至多方合作的时候。总是按照“甲方请求一次,乙方应答一次”这样的有序序列处理业务,只有当“一次请求一次应答”的过程 结束才可以发生下一次的“一次请求一次应答”,那么就说他们采用的是同步。(同步IO中,对同一个描述符的操作必须是有序的)
        如果甲方只要有需要,就会发送请求,不管上次请求有没有得到乙方应答。而乙方只要甲方有请求就会接受,不是等这次请求处理完毕再接受甲方新请求。这样请求应答分开的序列,就可以认为是异步。异步情况下,请求和应答不需要一致进行,可能甲方后请求的业务,却先得到乙方的应答。同步是线性的,而异步可以认为是并发的。(异步IO中,异步IO可以允许多方同时对同一个描述符发送IO请求,或者一次发多个请求,当然有机制保证如何区分这些请求,)

  1. 我去买一本书,立即买到了,或者没有就走了,这就是非阻塞;(编程中设置IO成非阻塞,返回后再去检查描述符,或者等待通知,然后再去读取。相当于老板告诉我可以先忙点别的,过一会再来问问,或者老板通知我。但期间这个窗口(文件描述符)别人是用不了的)("立即买到了"在IO中也需要等待,不能算非阻塞IO)
  2. 如果恰好书店没有,我就等一直等到书店有了这本书买到了才走,这就是阻塞;而排在我后面的人呢只有我买到了书后才能再买书了。
  3. 如果书店恰好没有,我就告诉书店老板,书来了告诉我一声让我来取或者直接送到我家,然后我就走了,去做别的事了,这就是异步。这时候如果很多人来买书,都是老板登记一下完事。 (从IO角度来说,“告诉我来取”,这个近似于信号驱动IO,不能算异步IO。必须书送到我家才算是异步,如果不送到我家,我想看这本书之前,终究还是需要我跑一趟)
  4. 前面两种情况,非阻塞和阻塞都可以称为同步。


2. 阻塞与非阻塞

        阻塞非阻塞: 进程/线程要访问的数据是否就绪,进程/线程是否需要等待。如果请求不能立即得到应答,需要等待,那就是阻塞;否则可以理解为非阻塞。

        阻塞和非阻塞关注的是程序在等待调用结果(消息,返回值)时的状态。阻塞调用是指调用结果返回之前,当前线程会被挂起。调用线程只有在得到结果之后才会返回。非阻塞调用指在不能立刻得到结果之前,该调用不会阻塞当前线程。还是上面的例子,你打电话问书店老板有没有《分布式系统》这本书,你如果是阻塞式调用,你会一直把自己“挂起”,直到得到这本书有没有的结果,如果是非阻塞式调用,你不管老板有没有告诉你,你自己先一边去玩了, 当然你也要偶尔过几分钟check一下老板有没有返回结果。在这里阻塞与非阻塞与是否同步异步无关。跟老板通过什么方式回答你结果无关。



同步与异步

  实际上同步与异步是针对应用程序与内核的交互而言的。同步过程中进程触发IO操作并等待或者轮询的去查看IO操作是否完成。异步过程中进程触发IO操作以后,直接返回,做自己的事情,IO交给内核来处理,完成后内核通知进程IO完成。


阻塞与非阻塞

  简单理解为需要做一件事能不能立即得到返回应答,如果不能立即获得返回,需要等待,那就阻塞了,否则就可以理解为非阻塞。


阻塞 / 非阻塞描述的是函数,指访问某个函数时是否会阻塞线程(block,线程进入阻塞状态)。
同步 / 异步描述的是执行IO操作的主体是谁,同步是由用户进程自己去执行最终的IO操作。异步是用户进程自己不关系实际IO操作的过程,只需要由内核在IO完成后通知它既可,由内核进程来执行最终的IO操作。



同步IO异步IO阻塞IO非阻塞IO


同步(synchronous) IO 和 异步(asynchronous) IO,阻塞(blocking) IO 和 非阻塞(non-blocking)IO 分别是什么,到底有什么区别?这个问题其实不同的人给出的答案都可能不同,比如wiki,就认为asynchronous IO和non-blocking IO是一个东西。这其实是因为不同的人的知识背景不同,并且在讨论这个问题的时候上下文(context)也不相同。所以,为了更好的回答这个问题,我先限定一下本文的上下文。
本文讨论的背景是Linux环境下的network IO。
本文最重要的参考文献是Richard Stevens的“UNIX® Network Programming Volume 1, Third Edition: The Sockets Networking”,6.2节“I/O Models”,Stevens在这节中详细说明了各种IO的特点和区别,如果英文够好的话,推荐直接阅读。Stevens的文风是有名的深入浅出,所以不用担心看不懂。本文中的流程图也是截取自参考文献。

 

Stevens在文章中一共比较了五种IO Model:blocking IO、nonblocking IO、IO multiplexing、signal driven IO、asynchronous IO。

由于signal driven IO在实际中并不常用,所以我这只提及剩下的四种IO Model。

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

对于一个network IO (这里我们以read举例),它会涉及到两个系统对象,一个是调用这个IO的process (or thread),另一个就是系统内核(kernel)。

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

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

记住这两点很重要,因为这些IO Model的区别就是在两个阶段上各有不同的情况。


blocking IO

在linux中,默认情况下所有的socket都是blocking,一个典型的读操作流程大概是这样:

当用户进程调用了recvfrom这个系统调用,kernel就开始了IO的第一个阶段:准备数据。对于network io来说,很多时候数据在一开始还没有到达(比如,还没有收到一个完整的UDP包),这个时候kernel就要等待足够的数据到来。而在用户进程这边,整个进程会被阻塞。当kernel一直等到数据准备好了,它就会将数据从kernel中拷贝到用户内存,然后kernel返回结果,用户进程才解除block的状态,重新运行起来。
所以,blocking IO的特点就是在IO执行的两个阶段都被block了。


下面以一个生动形象的例子来说明这四个概念。周末我和女友去逛街,中午饿了,我们准备去吃饭。周末人多,吃饭需要排队,我和女友有以下几种方案:
  (1)我和女友点完餐后,不知道什么时候能做好,只好坐在餐厅里面等,直到做好,然后吃完才离开。女友本想还和我一起逛街的,但是不知道饭能什么时候做好,只好和我一起在餐厅等,而不能去逛街,直到吃完饭才能去逛街,中间等待做饭的时间浪费掉了。这就是典型的阻塞。网络中IO阻塞如下图所示:





non-blocking IO

linux下,可以通过设置socket使其变为non-blocking。当对一个non-blocking socket执行读操作时,流程是这个样子:

从图中可以看出,当用户进程发出read操作时,如果kernel中的数据还没有准备好,那么它并不会block用户进程,而是立刻返回一个error。从用户进程角度讲 ,它发起一个read操作后,并不需要等待,而是马上就得到了一个结果。用户进程判断结果是一个error时,它就知道数据还没有准备好,于是它可以再次发送read操作。一旦kernel中的数据准备好了,并且又再次收到了用户进程的system call,那么它马上就将数据拷贝到了用户内存,然后返回。
所以,用户进程其实是需要不断的主动询问kernel数据好了没有。即需要不断的   轮询   kernel 数据好了没有


(2)接上面例子。我女友不甘心白白在这等,又想去逛商场,又担心饭好了。所以我们逛一会,回来询问服务员饭好了没有,来来回回好多次,饭都还没吃都快累死了啦。这就是非阻塞。需要不断的询问,是否准备好了。网络IO非阻塞如下图所示:



IO multiplexing

IO multiplexing这个词可能有点陌生,但是如果我说select,epoll,大概就都能明白了。有些地方也称这种IO方式为event driven IO。我们都知道,select/epoll的好处就在于单个process就可以同时处理多个网络连接的IO。它的基本原理就是select/epoll这个function会不断的轮询所负责的所有socket,当某个socket有数据到达了,就通知用户进程。它的流程如图:

当用户进程调用了select,那么整个进程会被block,而同时,kernel会“监视”所有select负责的socket,当任何一个socket中的数据准备好了,select就会返回。这个时候用户进程再调用read操作,将数据从kernel拷贝到用户进程。
这个图和blocking IO的图其实并没有太大的不同,事实上,还更差一些。因为这里需要使用两个system call (select 和 recvfrom),而blocking IO只调用了一个system call (recvfrom)。但是,用select的优势在于它可以同时处理多个connection。(多说一句。所以,如果处理的连接数不是很高的话,使用select/epoll的web server不一定比使用multi-threading + blocking IO的web server性能更好,可能延迟还更大。select/epoll的优势并不是对于单个连接能处理得更快,而是在于能处理更多的连接。)
在IO multiplexing Model中,实际中,对于每一个socket,一般都设置成为non-blocking,但是,如上图所示,整个用户的process其实是一直被block的。只不过process是被select这个函数block,而不是被socket IO给block。


(3)接上面例子。与第二个方案差不多,餐厅安装了电子屏幕用来显示点餐的状态,这样我和女友逛街一会,回来就不用去询问服务员了,直接看电子屏幕就可以了。这样每个人的餐是否好了,都直接看电子屏幕就可以了,这就是典型的IO多路复用,如select、poll、epoll。网络IO具体模型如下图所示:



Asynchronous I/O

linux下的asynchronous IO其实用得很少。先看一下它的流程:

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


(4)接上面例子。女友不想逛街,又餐厅太吵了,回家好好休息一下。于是我们叫外卖,打个电话点餐,然后我和女友可以在家好好休息一下,饭好了送货员送到家里来。这就是典型的异步,只需要打个电话说一下,然后可以做自己的事情,饭好了就送来了。linux提供了AIO库函数实现异步,但是用的很少。目前有很多开源的异步IO库,例如libevent、libev、libuv。异步过程如下图所示:



到目前为止,已经将四个IO Model都介绍完了。现在回过头来回答最初的那几个问题:blocking和non-blocking的区别在哪,synchronous IO和asynchronous IO的区别在哪。
先回答最简单的这个:blocking vs non-blocking。前面的介绍中其实已经很明确的说明了这两者的区别。调用blocking IO会一直block住对应的进程直到操作完成,而non-blocking IO在kernel还准备数据的情况下会立刻返回。

在说明synchronous IO和asynchronous IO的区别之前,需要先给出两者的定义。Stevens给出的定义(其实是POSIX的定义)是这样子的:

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

    一个同步 I/O 操作会引起请求处理被阻塞 至到 I/O 操作完成,阻塞解除。

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

    一个异步 I/O 操作不会引起请求处理被阻塞

两者的区别就在于synchronous IO做”IO operation”的时候会将process阻塞。按照这个定义,之前所述的blocking IO,non-blocking IO,IO multiplexing都属于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的比较如图所示:

经过上面的介绍,会发现non-blocking IO和asynchronous IO的区别还是很明显的。在non-blocking IO中,虽然进程大部分时间都不会被block,但是它仍然要求进程去主动的check,并且当数据准备完成以后,也需要进程主动的再次调用recvfrom来将数据拷贝到用户内存。而asynchronous IO则完全不同。它就像是用户进程将整个IO操作交给了他人(kernel)完成,然后他人做完后发信号通知。在此期间,用户进程不需要去检查IO操作的状态,也不需要主动的去拷贝数据。

最后,再举几个不是很恰当的例子来说明这四个IO Model:
有A,B,C,D四个人在钓鱼:
A用的是最老式的鱼竿,所以呢,得一直守着,等到鱼上钩了再拉杆;
B的鱼竿有个功能,能够显示是否有鱼上钩,所以呢,B就和旁边的MM聊天,隔会再看看有没有鱼上钩,有的话就迅速拉杆;
C用的鱼竿和B差不多,但他想了一个好办法,就是同时放好几根鱼竿,然后守在旁边,一旦有显示说鱼上钩了,它就将对应的鱼竿拉起来;
D是个有钱人,干脆雇了一个人帮他钓鱼,一旦那个人把鱼钓上来了,就给D发个短信。




本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/496319.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

java treeset比较,java中TreeSet的两种排序比较的方式

第一种是使得元素具有比较性第二种是让集合具有比较性具体代码步骤如下:import java.util.*;/** TreeSet:可以自动对对集合中的元素进行排序* 第一种比较方式* 步骤:* 1.让元素对象的类具有比较性,并实现Comparable接口* 2.对其中…

在 IE 中使用 HTML5 元素

一个HTML5范本 <html><head><style>blah {color:red;}</style></head><body><blah>Hello!</blah></body></html>一个简洁的 方法 让样式在 IE 中作用到未知的元素上——仅需 JS 创建此未知元素即可&#xff1a; &…

微软 AI 设计原则:成为弱者,再带来惊喜

来源&#xff1a;36Kr 作者&#xff1a;木木子编者按&#xff1a;AI设计的思路是什么&#xff1f;更完美&#xff1f;更能想用户之所想&#xff1f;本文作者Cliff Kuang在“The company studied personal assistants–human ones–to understand how to make a great machine…

vim 中的杀手级插件: vundle (vim 插件管理器)

From&#xff1a;http://zuyunfei.com/2013/04/12/killer-plugin-of-vim-vundle/ vundle.txt&#xff1a;https://github.com/VundleVim/Vundle.vim/blob/master/doc/vundle.txt Vundle 的具体介绍和配置&#xff1a;github repo&#xff1a;https://github.com/gmarik/vundl…

同步锁 php,python线程中同步锁详解

这篇文章主要为大家详细介绍了python线程中同步锁的相关资料&#xff0c;具有一定的参考价值&#xff0c;感兴趣的小伙伴们可以参考一下在使用多线程的应用下&#xff0c;如何保证线程安全&#xff0c;以及线程之间的同步&#xff0c;或者访问共享变量等问题是十分棘手的问题&a…

移动平均线分析法

移动平均线分析法是由道琼斯股价理论演变出来的一种股价趋势分析方法。其基本思想是消除股价随机波动的影响&#xff0c;以寻求股价波动的趋势。主要特点&#xff1a;1、追踪趋势&#xff1a;MA能够表示股价波动的趋势&#xff0c;并追踪这个趋势不轻易改变。2、滞后性&#xf…

Spring Data JPA 从入门到精通~Auditing及其事件详解

Auditing 及其事件详解 Auditing 翻译过来是审计和审核&#xff0c;Spring 的优秀之处在于帮我们想到了很多繁琐事情的解决方案&#xff0c;我们在实际的业务系统中&#xff0c;针对一张表的操作大部分是需要记录谁什么时间创建的&#xff0c;谁什么时间修改的&#xff0c;并且…

未来城市的无人机送货系统是怎样的?

来源&#xff1a; 资本实验室 作者&#xff1a;李鑫Siri通过移动应用下了一盒巴克拉拉面膜的订单&#xff0c;电商平台收到信息&#xff0c;发指令给最近的送货驳船。驳船上的无人机获取货物包裹后直接飞向Siri家。在不到8分钟的飞行后&#xff0c;无人机来到位于12层的Siri家…

Vim自动补全神器:YouCompleteMe

From&#xff1a;http://www.jianshu.com/p/d908ce81017a github 地址&#xff1a;https://github.com/Valloric/YouCompleteMe YouCompleteMe is a fast, as-you-type, fuzzy-search code completion engine for Vim. 参考&#xff1a; https://github.com/Valloric/YouCom…

故障树分析法MATLAB,故障树分析(FTA)方法及其基于VC的软件设计的研究

故障树分析法(FTA)是一种评价复杂系统可靠性与安全性的重要方法。经过近四十年的发展,FTA技术已经有相对成熟的理论,但是在FTA的组合爆炸困难(计算量随故障树规模指数增长)、相关底事件的FTA 等方面还有待于进一步的研究。而且随着系统复杂性的加大,系统所含部件愈来愈多,研究系…

Windows 7硬盘安装方法大全

Windows 7硬盘安装方法大全&#xff0c;共整理出四种方法该Windows 7硬盘安装方法大全介绍了Windows 7下安装高版本的Windows 7&#xff0c;Vista下硬盘安装Windows 7&#xff0c;xp下硬盘安装Windows7等方法&#xff01; 一、 windows 7 系统下全新安装高版Windows7&#xff1…

对比 | 欧洲、美国、中国智慧城市的不同实践路径

来源&#xff1a;《上海城市规划》2018年第1期《欧美智慧城市最新实践与参考》作者&#xff1a;刘杨 龚烁 刘晋媛随着ICT、大数据、物联网等各类新兴技术的不断发展&#xff0c;智慧城市的运营和实践也不断趋于成熟。通过整理欧美各大典型智慧城市的最新实践案例&#xff0c;总…

C++ 使用 TinyXml 解析 XML 文件

知乎 C解析xml有什么好用的轮子? &#xff1a;https://www.zhihu.com/question/32046606 TinyXML-2 的 github地址和帮助文档&#xff1a;https://github.com/leethomason/tinyxml2 tinyxml 下载地址&#xff1a;https://sourceforge.net/projects/tinyxml/ *Please Note*…

java1.8.0,jdk1.8.0版本

【实例简介】jdk1.8版本&#xff0c;亲测可用。望有需求人士放心使用&#xff0c;下载。【实例截图】【核心代码】31449426-2a86-4e86-9718-9b4327dbb178└── jdk-8u161-windows-x64├── 1041│ ├── [5]DigitalSignature│ ├── [5]MsiDigitalSignatureEx│ ├─…

定制自己的Windows CE 5.0 ARM中文模拟器(转)

定制自己的Windows CE 5.0 ARM中文模拟器(转)http://showvi.com/Blog/ViewAirticle/59一、生成OS 1. 安装Windows CE 5.0&#xff08;记得CPU类型里把ARMV4I选上&#xff09;装完之后装DeviceEmulatorBSP.msi&#xff0c;这是ARMV4I模拟器的BSP。 我补充个DeviceEmulatorBSP.ms…

Spring Data JPA 从入门到精通~@Version处理乐观锁的问题

Version 处理乐观锁的问题 Version 乐观锁介绍 我们在研究 Auditing 的时候&#xff0c;发现了一个有趣的注解 Version&#xff0c;源码如下&#xff1a; package org.springframework.data.annotation; /*** Demarcates a property to be used as version field to impleme…

人工智能即服务 当人工智能遇到云计算

来源&#xff1a;企业网为了在竞争中保持领先地位&#xff0c;越来越多的企业正在寻求将人工智能技术整合到其应用程序、产品、服务&#xff0c;以及大数据分析方法中。而企业开始使用人工智能技术的最简单和最流行的方法之一是使用基于云计算的人工智能即服务产品。根据调研机…

视频裁剪

用【格式工厂FFSetup190.exe】将视频文件格式专程AVI, 再用视频裁剪工具【SolveigMM AVI Trimmer】裁剪需要的段。 源文件-添加视频文件-填入开始时间和停止时间&#xff08;用三耳确定填写的时间值&#xff09;-按添加按钮-选择目的文件路径及名称-运行。 转载于:https://www.…

三星s9php禁用列表,ADB禁用列表

该楼层疑似违规已被系统折叠 隐藏此楼查看此楼谷歌程序pm uninstall --user 0com.google.android.ext.servicespm uninstall --user 0com.google.android.onetimeinitializerpm uninstall --user 0com.google.android.ext.sharedpm uninstall --user 0com.google.android.confi…

Linux 文件 IO

参考&#xff1a;http://blog.csdn.net/wanxiao009/article/details/5648583 C 和 C 文件操作详解&#xff1a;http://blog.csdn.net/freeking101/article/details/60959624 标准IO与文件IO 的区别&#xff1a;http://blog.csdn.net/big_bit/article/details/51804391 参考…