异步非阻塞_同步异步阻塞非阻塞 - CSDN
精华内容
参与话题
  • 同步异步/阻塞非阻塞

    千次阅读 2019-05-27 16:47:05
    网络中获取数据的读操作步骤: 等待数据准备。...如果是异步操作,那么它会去做别的事情,等待数据准备好,内核通知它,它再去读取数据。 同步过程中进程触发IO操作并等待或者轮询的去查看IO操作是否完...

    网络中获取数据的读操作步骤:
    等待数据准备。
    数据从内核空间拷贝到用户空间。

    同步与异步:
    同步与异步是针对应用程序与内核的交互而言。也就是上图的read操作,从缓存中读取数据,如果缓存中数据还没有准备好,如果是同步操作,它会一直等待,直到操作完成。如果是异步操作,那么它会去做别的事情,等待数据准备好,内核通知它,它再去读取数据。

    同步过程中进程触发IO操作并等待或者轮询的去查看IO操作是否完成。
    异步过程中进程触发IO操作以后,直接返回,做自己的事情,IO操作交给内核来处理,完成后内核通知进程IO完成。
    同步和异步是相对于操作结果来说,会不会等待结果返回。
    阻塞与非阻塞:
    应用进程请求IO操作时,如果数据未准备好,如果请求立即返回就是非阻塞,不立即返回就是阻塞。简单来说,就是做一件事如果不能立即获得返回,需要等待,就是阻塞,否则可以理解为非阻塞。

    阻塞和非阻塞是相对于线程是否被阻塞。
    异步/同步和阻塞/非阻塞的区别:
    其实,这两者存在本质区别,他们的修饰对象是不同的。 阻塞和非阻塞是指进程访问的数据如果尚未准备就绪,进程是否需要等待,简单来说这相当于函数内部的实现区别 ,也就是未就绪时是直接返回还是等待就绪。
    而同步和异步是指访问数据的机制 ,同步一般指主动请求并等待IO操作完毕的方式 ,当数据就绪后再读写的时候必须阻塞,异步则指主动请求数据后便可以继续处理其它任务,随后等待IO操作完毕的通知,这可以使进程再数据读写时也不阻塞。

    同步/异步 与 阻塞/非阻塞的组合方式
    故事:老王烧开水
    出场人物:老王,两把水壶(水壶,响水壶)

    同步阻塞: 效率是最低的,实际程序中,就是fd未设置O_NONBLOCK 标志位的read/write操作。
    老王用水壶烧水,并且站在那里(阻塞),不管水开没开,每隔一定时间看看水开了没(同步->轮询)。
    同步非阻塞: 实际上效率是低下的,注意对fd设置O_NONBLOCK 标志位。
    老王用水壶烧水,不再傻傻的站在那里,跑去做别的事情(非阻塞),但是还是会每个一段时间过来看看水开了没,没开就继续去做的事情(同步->轮询)。
    异步阻塞: 异步操作是可以被阻塞住的,只不过它不是在处理消息时阻塞,而是在等待消息时被阻塞。比如select函数,假如传入的最后一个timeout函数为NULL,那么如果所关注的事件没有一个被触发,程序就会一直阻塞在select调用处。
    老王用响水壶烧水,站在那里(阻塞),但是不再去看水开了没,而是等水开了,水壶会自动通知它(异步,内核通知进程)。
    异步非阻塞: 效率更高,注册一个回调函数,就可以去做别的事情。
    老王用响水壶烧水。跑去做别的事情(非阻塞),等待响水壶烧开水自动通知它(异步,内核通知进程)
    socket的fd是什么?
    fd是(file descriptor/文件描述符) ,这种一般是BSD Socket的用法,用在Unix/linux系统上。在Unix/linux系统下,一个Socket句柄,可以看做是一个文件,在socket上收发数据,相当于读一个文件进行读写,所以一个socket句柄,通常也用表示文件句柄的fd来表示。

    缓存IO
    缓存IO又被称为标准IO,大多数文件系统的默认IO操作都是缓存IO。 在linux的缓存IO机制中,操作系统会将IO的数据缓存在文件系统的页缓存(page cache)中,也就是说,数据会先被拷贝到操作系统内核的缓冲区中,然后才会从操作系统内核的缓冲区拷贝到应用程序的地址空间。

    缓存IO缺点:
    数据在传输过程中需要在应用程序地址空间和内核空间进行多次数据拷贝操作,这些数据拷贝带来的CPU以及内存开销是非常大的。
    https://blog.csdn.net/Fly_Fly_Zhang/article/details/90380005

    ============================================================

    近来遇到了一些常见的概念,尤其是网络编程方面的概念,如:阻塞、非阻塞、异步I/O等等,对于这些概念自己也没有太清晰的认识,只是很模糊的概念,说了解吧也了解,但是要让自己准确的描述概念方面的具体细节,却说的不那么准确,这也是自己在这几个方面也没有细细考究过的原因吧。经过看了些这几个概念的资料,发现同步、异步、阻塞、非阻塞的概念其实也并不难以理解,在此写下此文,欢迎拍砖,希望多多交流。

    1 同步与异步#

    首先来解释同步和异步的概念,这两个概念与消息的通知机制有关。也就是同步与异步主要是从消息通知机制角度来说的。

    1.1 概念描述##

    所谓同步就是一个任务的完成需要依赖另外一个任务时,只有等待被依赖的任务完成后,依赖的任务才能算完成,这是一种可靠的任务序列。要么成功都成功,失败都失败,两个任务的状态可以保持一致。

    所谓异步是不需要等待被依赖的任务完成,只是通知被依赖的任务要完成什么工作,依赖的任务也立即执行,只要自己完成了整个任务就算完成了。至于被依赖的任务最终是否真正完成,依赖它的任务无法确定,所以它是不可靠的任务序列

    1.2 消息通知##

    异步的概念和同步相对。当一个同步调用发出后,调用者要一直等待返回消息(结果)通知后,才能进行后续的执行;当一个异步过程调用发出后,调用者不能立刻得到返回消息(结果)。实际处理这个调用的部件在完成后,通过状态、通知和回调来通知调用者

    这里提到执行部件和调用者通过三种途径返回结果:状态、通知和回调。使用哪一种通知机制,依赖于执行部件的实现,除非执行部件提供多种选择,否则不受调用者控制

    1. 如果执行部件用状态来通知,那么调用者就需要每隔一定时间检查一次,效率就很低(有些初学多线程编程的人,总喜欢用一个循环去检查某个变量的值,这其实是一种很严重的错误);

    2. 如果是使用通知的方式,效率则很高,因为执行部件几乎不需要做额外的操作。至于回调函数,其实和通知没太多区别。

    1.2 场景比喻##

    举个例子,比如我去银行办理业务,可能会有两种方式:

    1. 选择排队等候;

    2. 另种选择取一个小纸条上面有我的号码,等到排到我这一号时由柜台的人通知我轮到我去办理业务了;

    第一种:前者(排队等候)就是同步等待消息通知,也就是我要一直在等待银行办理业务情况;

    第二种:后者(等待别人通知)就是异步等待消息通知。在异步消息处理中,等待消息通知者(在这个例子中就是等待办理业务的人)往往注册一个回调机制,在所等待的事件被触发时由触发机制(在这里是柜台的人)通过某种机制(在这里是写在小纸条上的号码,喊号)找到等待该事件的人。

    2 阻塞与非阻塞#

    阻塞和非阻塞这两个概念与程序(线程)等待消息通知(无所谓同步或者异步)时的状态有关。也就是说阻塞与非阻塞主要是程序(线程)等待消息通知时的状态角度来说的。

    2.1 概念描述##

    阻塞调用是指调用结果返回之前,当前线程会被挂起,一直处于等待消息通知,不能够执行其他业务。函数只有在得到结果之后才会返回。

    有人也许会把阻塞调用和同步调用等同起来,实际上它们是不同的。

    1. 对于同步调用来说,很多时候当前线程可能还是激活的,只是从逻辑上当前函数没有返回而已,此时,这个线程可能也会处理其他的消息。还有一点,在这里先扩展下:

    (a) 如果这个线程在等待当前函数返回时,仍在执行其他消息处理,那这种情况就叫做同步非阻塞;

    (b) 如果这个线程在等待当前函数返回时,没有执行其他消息处理,而是处于挂起等待状态,那这种情况就叫做同步阻塞;

    所以同步的实现方式会有两种:同步阻塞、同步非阻塞;同理,异步也会有两种实现:异步阻塞、异步非阻塞;

    1. 对于阻塞调用来说,则当前线程就会被挂起等待当前函数返回;

    非阻塞和阻塞的概念相对应,指在不能立刻得到结果之前,该函数不会阻塞当前线程,而会立刻返回。虽然表面上看非阻塞的方式可以明显的提高CPU的利用率,但是也带了另外一种后果就是系统的线程切换增加增加的CPU执行时间能不能补偿系统的切换成本需要好好评估

    2.2 场景比喻##

    继续上面的那个例子,不论是排队还是使用号码等待通知,如果在这个等待的过程中,等待者除了等待消息通知之外不能做其它的事情,那么该机制就是阻塞的,表现在程序中,也就是该程序一直阻塞在该函数调用处不能继续往下执行。

    相反,有的人喜欢在银行办理这些业务的时候一边打打电话发发短信一边等待,这样的状态就是非阻塞的,因为他(等待者)没有阻塞在这个消息通知上,而是一边做自己的事情一边等待。

    但是需要注意了,同步非阻塞形式实际上是效率低下的,想象一下你一边打着电话一边还需要抬头看到底队伍排到你了没有。如果把打电话和观察排队的位置看成是程序的两个操作的话,这个程序需要在这两种不同的行为之间来回的切换,效率可想而知是低下的;而异步非阻塞形式却没有这样的问题,因为打电话是你(等待者)的事情,而通知你则是柜台(消息触发机制)的事情,程序没有在两种不同的操作中来回切换。

    3 同步/异步与阻塞/非阻塞#

    1. 同步阻塞形式

    效率是最低的,

    拿上面的例子来说,就是你专心排队,什么别的事都不做。

    实际程序中:就是未对fd 设置O_NONBLOCK标志位的read/write 操作;

    1. 异步阻塞形式

    如果在银行等待办理业务的人采用的是异步的方式去等待消息被触发(通知),也就是领了一张小纸条,假如在这段时间里他不能离开银行做其它的事情,那么很显然,这个人被阻塞在了这个等待的操作上面;

    异步操作是可以被阻塞住的,只不过它不是在处理消息时阻塞,而是在等待消息通知时被阻塞。

    比如select 函数,假如传入的最后一个timeout参数为NULL,那么如果所关注的事件没有一个被触发,程序就会一直阻塞在这个select 调用处

    1. 同步非阻塞形式

    实际上是效率低下的,

    想象一下你一边打着电话一边还需要抬头看到底队伍排到你了没有,如果把打电话和观察排队的位置看成是程序的两个操作的话,这个程序需要在这两种不同的行为之间来回的切换,效率可想而知是低下的。

    很多人会写阻塞的read/write 操作,但是别忘了可以对fd设置O_NONBLOCK 标志位,这样就可以将同步操作变成非阻塞的了

    1. 异步非阻塞形式

    效率更高,

    因为打电话是你(等待者)的事情,而通知你则是柜台(消息触发机制)的事情,程序没有在两种不同的操作中来回切换

    比如说,这个人突然发觉自己烟瘾犯了,需要出去抽根烟,于是他告诉大堂经理说,排到我这个号码的时候麻烦到外面通知我一下(注册一个回调函数),那么他就没有被阻塞在这个等待的操作上面,自然这个就是异步+非阻塞的方式了。

    如果使用异步非阻塞的情况,比如aio_*组的操作,当发起一个aio_read操作时,函数会马上返回不会被阻塞,当所关注的事件被触发时会调用之前注册的回调函数进行处理

    很多人会把同步和阻塞混淆,我想是因为很多时候同步操作会以阻塞的形式表现出来,比如很多人会写阻塞的read/write操作,但是别忘了可以对fd设置O_NONBLOCK标志位,这样就可以将同步操作变成非阻塞的了。但最根本是因为没有区分这两个概念,比如阻塞的read/write操作中,其实是把消息通知机制和等待消息通知的状态结合在了一起,在这里所关注的消息就是fd是否可读/写,而等待消息通知的状态则是对fd可读/写等待过程中程序(线程)的状态。当我们将这个fd设置为非阻塞的时候,read/write操作就不会在等待消息通知这里阻塞,如果fd不可读/写则操作立即返回。

    同样的,很多人也会把异步和非阻塞混淆,因为异步操作一般都不会在真正的IO操作处被阻塞,比如如果用select函数,当select返回可读时再去read一般都不会被阻塞,而是在select函数调用处阻塞

    4 小明的故事#

    对上面所讲的概念再次进行一个场景梳理,上面已经明确说明,同步/异步关注的是消息通知的机制,而阻塞/非阻塞关注的是程序(线程)等待消息通知时的状态。以小明下载文件打个比方,从这两个关注点来再次说明这两组概念,希望能够更好的促进大家的理解。

    1. 同步阻塞:小明一直盯着下载进度条,到 100% 的时候就完成。

    同步体现在:等待下载完成通知;

    阻塞体现在:等待下载完成通知过程中,不能做其他任务处理;

    1. 同步非阻塞:小明提交下载任务后就去干别的,每过一段时间就去瞄一眼进度条,看到 100% 就完成。

    同步体现在:等待下载完成通知;

    非阻塞体现在:等待下载完成通知过程中,去干别的任务了,只是时不时会瞄一眼进度条;【小明必须要在两个任务间切换,关注下载进度】

    1. 异步阻塞:小明换了个有下载完成通知功能的软件,下载完成就“叮”一声。不过小明仍然一直等待“叮”的声音(看起来很傻,不是吗)。

    异步体现在:下载完成“叮”一声通知;

    阻塞体现在:等待下载完成“叮”一声通知过程中,不能做其他任务处理;

    1. 异步非阻塞:仍然是那个会“叮”一声的下载软件,小明提交下载任务后就去干别的,听到“叮”的一声就知道完成了。

    异步体现在:下载完成“叮”一声通知;

    非阻塞体现在:等待下载完成“叮”一声通知过程中,去干别的任务了,只需要接收“叮”声通知即可;【软件处理下载任务,小明处理其他任务,不需关注进度,只需接收软件“叮”声通知,即可】

    也就是说,同步/异步是“下载完成消息”通知的方式(机制),而阻塞/非阻塞则是在等待“下载完成消息”通知过程中的状态(能不能干其他任务),在不同的场景下,同步/异步、阻塞/非阻塞的四种组合都有应用。

    所以,综上所述,同步和异步仅仅是关注的消息如何通知的机制,而阻塞与非阻塞关注的是等待消息通知时的状态。也就是说,同步的情况下,是由处理消息者自己去等待消息是否被触发,而异步的情况下是由触发机制来通知处理消息者,所以在异步机制中,处理消息者和触发机制之间就需要一个连接的桥梁

    在银行的例子中,这个桥梁就是小纸条上面的号码。

    在小明的例子中,这个桥梁就是软件“叮”的声音。

    最后,请大家注意理解“消息通知机制”和“等待消息通知时的状态”这两个概念,这是理解四个概念的关键所在。
    链接:https://www.jianshu.com/p/aed6067eeac9
     

    展开全文
  • 同步/异步,阻塞/非阻塞概念深度解析

    万次阅读 多人点赞 2019-06-25 14:38:31
    IO 概念区分NIO 现在已经是一个耳熟能详的名词了, 好像人人都能对所谓的 NIO ( Non-Blocking IO, 非阻塞 IO ) 发表一些如何如何提高效率的言论。 但很多东西, 追问几句就会难以自圆其说。 四个相关概念: 同步...

    IO 概念区分

    NIO 现在已经是一个耳熟能详的名词了, 好像人人都能对所谓的 NIO ( Non-Blocking IO, 非阻塞 IO ) 发表一些如何如何提高效率的言论。 但很多东西, 追问几句就会难以自圆其说。

    四个相关概念:

    • 同步(Synchronous)
    • 异步( Asynchronous)
    • 阻塞( Blocking )
    • 非阻塞( Nonblocking)

    这四个概念的含义以及相互之间的区别与联系,并不如很多网络博客所写的那么简单, 通过举一些什么商店购物, 买书买报的例子就能讲清楚。

    进程通信上下文的同步/异步, 阻塞/非阻塞

    首先强调一点, 网络上的很多博文关于同步/异步, 阻塞非阻塞区别的解释其实都很经不起推敲。 例如怎样理解阻塞非阻塞与同步异步的区别 这一高赞回答中 , 有如下解释(不准确):

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

      • 所谓同步,就是在发出一个调用时,在没有得到结果之前, 该调用就不返回。
      • 异步则是相反,调用在发出之后,这个调用就直接返回了,所以没有返回结果
    • 阻塞/非阻塞关注的是程序在等待调用结果(消息,返回值)时的状态.

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

    粗一看, 好像同步/ 非同步阻塞/非阻塞 是两种维度的概念, 可以分别对待, 但是稍微推敲一下就会发现上述的解释根本难以自圆其说。

    • 如果**“同步”** 是发起了一个调用后, 没有得到结果之前不返回, 那它毫无疑问就是被"阻塞"了(即调用进程处于 “waiting” 状态)。
    • 如果调用发出了以后就直接返回了, 毫无疑问, 这个进程没有被“阻塞”。

    所以, 上述的解释是不准确的。 让我们看一下《操作系统概念(第九版)》中有关进程间通信的部分是如何解释的:

    这里写图片描述

    翻译一下就是:

    进程间的通信时通过 send() 和 receive() 两种基本操作完成的。具体如何实现这两种基础操作,存在着不同的设计。
    消息的传递有可能是**阻塞的**或**非阻塞的** -- 也被称为**同步**或**异步**的

    • 阻塞式发送(blocking send). 发送方进程会被一直阻塞, 直到消息被接受方进程收到。
    • 非阻塞式发送(nonblocking send)。 发送方进程调用 send() 后, 立即就可以其他操作。
    • 阻塞式接收(blocking receive) 接收方调用 receive() 后一直阻塞, 直到消息到达可用。
    • 非阻塞式接受(nonblocking receive) 接收方调用 receive() 函数后, 要么得到一个有效的结果, 要么得到一个空值, 即不会被阻塞。

    上述不同类型的发送方式和不同类型的接收方式,可以自由组合。

    • 也就是说, 从进程级通信的维度讨论时, 阻塞和同步(非阻塞和异步)就是一对同义词, 且需要针对发送方接收方作区分对待。

    先修知识

    • 用户空间和内核空间
    • 进程切换
      • 系统调用(system call)
      • 中断(interrupt)
    • 进程的阻塞

    用户空间和内核空间

    操作系统为了支持多个应用同时运行,需要保证不同进程之间相对独立(一个进程的崩溃不会影响其他的进程 , 恶意进程不能直接读取和修改其他进程运行时的代码和数据)。 因此操作系统内核需要拥有高于普通进程的权限, 以此来调度和管理用户的应用程序。

    于是内存空间被划分为两部分,一部分为内核空间,一部分为用户空间,内核空间存储的代码和数据具有更高级别的权限。内存访问的相关硬件在程序执行期间会进行访问控制( Access Control),使得用户空间的程序不能直接读写内核空间的内存。

    • 有《微机原理》 课程基础同学可以 Google 搜索 DPL, CPL 这两个关键字了解硬件层面的内存访问权限控制细节

    进程切换

    这里写图片描述

    上图展示了进程切换中几个最重要的步骤:

    1. 当一个程序正在执行的过程中, 中断(interrupt) 或 系统调用(system call) 发生可以使得 CPU 的控制权会从当前进程转移到操作系统内核。
    2. 操作系统内核负责保存进程 i 在 CPU 中的上下文(程序计数器, 寄存器)到 PCBiPCB_iPCBi (操作系统分配给进程的一个内存块)中。
    3. PCBjPCB_jPCBj 取出进程 j 的CPU 上下文, 将 CPU 控制权转移给进程 j , 开始执行进程 j 的指令。

    几个底层概念的通俗(不严谨)解释:

    • 中断(interrupt)

      • CPU 微处理器有一个中断信号位, 在每个CPU时钟周期的末尾, CPU会去检测那个中断信号位是否有中断信号到达, 如果有, 则会根据中断优先级决定是否要暂停当前执行的指令, 转而去执行处理中断的指令。 (其实就是 CPU 层级的 while 轮询)
    • 时钟中断( Clock Interrupt )

      • 一个硬件时钟会每隔一段(很短)的时间就产生一个中断信号发送给 CPU,CPU 在响应这个中断时, 就会去执行操作系统内核的指令, 继而将 CPU 的控制权转移给了操作系统内核, 可以由操作系统内核决定下一个要被执行的指令。
    • 系统调用(system call)

      • system call 是操作系统提供给应用程序的接口。 用户通过调用 systemcall 来完成那些需要操作系统内核进行的操作, 例如硬盘, 网络接口设备的读写等。

    从上述描述中, 可以看出来, 操作系统在进行进切换时,需要进行一系列的内存读写操作, 这带来了一定的开销:

    • 对于一个运行着 UNIX 系统的现代 PC 来说, 进程切换至少需要花费 300 us 的时间

    进程阻塞

    这里写图片描述
    上图展示了一个进程的不同状态:

    • New。 进程正在被创建.
    • Running. 进程的指令正在被执行
    • Waiting. 进程正在等待一些事件的发生(例如 I/O 的完成或者收到某个信号)。
    • Ready. 进程在等待被操作系统调度。
    • Terminated. 进程执行完毕(可能是被强行终止的)。

    我们所说的 “阻塞”是指进程在发起了一个系统调用(System Call) 后, 由于该系统调用的操作不能立即完成,需要等待一段时间,于是内核将进程挂起为**等待 (waiting)**状态, 以确保它不会被调度执行, 占用 CPU 资源。

    • 友情提示: 在任意时刻, 一个 CPU 核心上(processor)只可能运行一个进程

    I/O System Call 的阻塞/非阻塞, 同步/异步

    这里再重新审视 阻塞/非阻塞 IO 这个概念, 其实阻塞和非阻塞描述的是进程的一个操作是否会使得进程转变为“等待”的状态, 但是为什么我们总是把它和 IO 连在一起讨论呢?

    原因是, 阻塞这个词是与系统调用 System Call 紧紧联系在一起的, 因为要让一个进程进入 等待(waiting) 的状态, 要么是它主动调用 wait() 或 sleep() 等挂起自己的操作, 另一种就是它调用 System Call, 而 System Call 因为涉及到了 I/O 操作, 不能立即完成, 于是内核就会先将该进程置为等待状态, 调度其他进程的运行, 等到 它所请求的 I/O 操作完成了以后, 再将其状态更改回 ready 。

    操作系统内核在执行 System Call 时, CPU 需要与 IO 设备完成一系列物理通信上的交互, 其实再一次会涉及到阻塞和非阻塞的问题, 例如, 操作系统发起了一个读硬盘的请求后, 其实是向硬盘设备通过总线发出了一个请求,它即可以阻塞式地等待IO 设备的返回结果,也可以非阻塞式的继续其他的操作。 在现代计算机中,这些物理通信操作基本都是异步完成的, 即发出请求后, 等待 I/O 设备的中断信号后, 再来读取相应的设备缓冲区。 但是,大部分操作系统默认为用户级应用程序提供的都是阻塞式的系统调用 (blocking systemcall)接口, 因为阻塞式的调用,使得应用级代码的编写更容易(代码的执!行顺序和编写顺序是一致的)。

    但同样, 现在的大部分操作系统也会提供非阻塞I/O 系统调用接口(Nonblocking I/O system call)。 一个非阻塞调用不会挂起调用程序, 而是会立即返回一个值, 表示有多少bytes 的数据被成功读取(或写入)。

    非阻塞I/O 系统调用( nonblocking system call )的另一个替代品是 异步I/O系统调用 (asychronous system call)。 与非阻塞 I/O 系统调用类似,asychronous system call 也是会立即返回, 不会等待 I/O 操作的完成, 应用程序可以继续执行其他的操作, 等到 I/O 操作完成了以后,操作系统会通知调用进程(设置一个用户空间特殊的变量值 或者 触发一个 signal 或者 产生一个软中断 或者 调用应用程序的回调函数)。

    此处, 非阻塞I/O 系统调用( nonblocking system call ) 和 **异步I/O系统调用 (asychronous system call)**的区别是:

    • 一个非阻塞I/O 系统调用 read() 操作立即返回的是任何可以立即拿到的数据, 可以是完整的结果, 也可以是不完整的结果, 还可以是一个空值。
    • 异步I/O系统调用 read()结果必须是完整的, 但是这个操作完成的通知可以延迟到将来的一个时间点。

    下图展示了同步I/O 与 异步 I/O 的区别 (非阻塞 IO 在下图中没有绘出).
    这里写图片描述

    注意, 上面提到的 非阻塞I/O 系统调用( nonblocking system call )异步I/O系统调用 都是非阻塞式的行为(non-blocking behavior)。 他们的差异仅仅是返回结果的方式和内容不同。

    非阻塞 I/O 如何帮助服务器提高吞吐量

    考虑一个单进程服务器程序, 收到一个 Socket 连接请求后, 读取请求中的文件名,然后读请求的文件名内容,将文件内容返回给客户端。 那么一个请求的处理流程会如下图所示。

    这里写图片描述

    • R 表示读操作
    • W 表示写操作
    • C 表示关闭操作

    在这个过程中, 我们可以看到, CPU 和 硬盘IO 的资源大部分时间都是闲置的。 此时, 我们会希望在等待 I/O 的过程中继续处理新的请求。

    方案一: 多进程

    • 每到达一个请求, 我们为这个请求新创建一个进程来处理。 这样, 一个进程在等待 IO 时, 其他的进程可以被调度执行, 更加充分地利用 CPU 等资源。
    • 问题: 每新创建一个进程都会消耗一定的内存空间, 且进程切换也会有时间消耗, 高并发时, 大量进程来回切换的时间开销会变得明显起来。

    方案二:多线程

    • 和多进程方案类似,为每一个请求新建一个线程进行处理,这样做的重要区别是, 所有的线程都共享同一个进程空间
    • 问题: 需要考虑是否需要为特定的逻辑使用锁。

    引申问题: 一个进程中的某一个线程发起了 system call 后, 是否造成整个进程的阻塞? 如果会, 那么多线程方案与单进程方案相比就没有明显的改善。

    • 解决办法1:内核支持的线程(kenerl supported threads)
      • 操作系统内核能够感知到线程, 每一个线程都会有一个内核调用栈(kenerl stack) 和 保存CPU 寄存器下文的 table 。

    这里写图片描述

    在这种方案中, 如果 CPU 是多核的, 不同的线程还可以运行在不同的 CPU processor 上。 既实现了IO 并发, 也实现了 CPU 并发。

    问题: 基于内核线程编写的应用会难以移植

    • 不同的操作系统对于内核线程的支持方式统而言有所差别,甚至部分操作系统甚至不支持内核级别线程, 当应用代码基于内核线程进行开发后, 就使得应用层代码与特定的操作系统产生了耦合关系, 不能随意部署

    • 解决办法2: 用户支持的线程(user supported threads)

      • 内核感知不到用户线程, 每一个用户的进程拥有一个调度器, 该调度器可以感知到线程发起的系统调用, 当一个线程产生系统调用时, 不阻塞整个进程, 切换到其他线程继续运行。 当 I/O 调用完成以后, 能够重新唤醒被阻塞的线程。
      • 实现细节:
        • 应用程序基于线程库 thread libray 编写
        • 线程库中包含 “虚假的” read(), write(), accept()等系统调用。
        • 线程库中的 read(), write(), accept() 的底层实现为非阻塞系统调用(Non-blocking system call), 调用后,由于可以立即返回, 则将特定的线程状态标记为 waiting, 调度其他的可执行线程。 内核完成了 IO 操作后, 调用线程库的回调函数, 将原来处于 waiting 状态的线程标记为 runnable.

    这里写图片描述
    从上面的过程可以看出,用户支持线程的解决方案基于非阻塞IO系统调用( non-blocking system call) , 且是一种基于操作系统内核事件通知(event-driven)的解决方案, 基于这个流程, 可以引申到更为宽泛的 event-driven progreamming 话题上。 但是这里就不作赘述了。

    总结:

    1. 阻塞/非阻塞, 同步/异步的概念要注意讨论的上下文:
    • 在进程通信层面, 阻塞/非阻塞, 同步/异步基本是同义词, 但是需要注意区分讨论的对象是发送方还是接收方。

      • 发送方阻塞/非阻塞(同步/异步)和接收方的阻塞/非阻塞(同步/异步) 是互不影响的。
    • 在 IO 系统调用层面( IO system call )层面, 非阻塞IO 系统调用 和 异步IO 系统调用存在着一定的差别, 它们都不会阻塞进程, 但是返回结果的方式和内容有所差别, 但是都属于非阻塞系统调用( non-blocing system call )

    1. 非阻塞系统调用(non-blocking I/O system call 与 asynchronous I/O system call) 的存在可以用来实现线程级别的 I/O 并发, 与通过多进程实现的 I/O 并发相比可以减少内存消耗以及进程切换的开销。
    展开全文
  • 同步 异步 阻塞 非阻塞 区别

    千次阅读 2018-09-25 10:27:27
     前一段时间出去面试,被问到同步、异步与阻塞、非阻塞的区别。我一时半会没有想出来,作为一个工作三年的人来说,实在很惭愧。我当时理解同步、异步属于两个进程中间的协作关系,例如使用浏览器访问一个网站,需要...

    https://www.cnblogs.com/Anker/p/5965654.html

     

    1、前言

      前一段时间出去面试,被问到同步、异步与阻塞、非阻塞的区别。我一时半会没有想出来,作为一个工作三年的人来说,实在很惭愧。我当时理解同步、异步属于两个进程中间的协作关系,例如使用浏览器访问一个网站,需要多次请求服务端,才能加载完整个页面的内容。同步的操作如下:浏览器首先发送第一个请求,等待服务器回复后,再发送第二个请求,依次类推,直到所有请求完成。异步的操作如下:浏览器发送第一个请求,可以不用等待服务器返回,可以继续发送第二个请求。阻塞与非阻塞属于进程的API执行动作的方式,例如进行需要read数据,阻塞方式操作流程是:如果没有数据,则read会一直等着数据到来,才能进行后续的动作;而非阻塞则是read没有到数据后,则可以进行后续的动作,当有数据的时候再回来读取。通常linux网络API默认都是阻塞的,例如connect、send、recv等。回答后感觉自己心里没有底,底层的关系到底是什么样的,比较虚,没能深入理解。

    2、深入理解分析  

      回来以后,赶紧上网好好查查,加深学习一下。这两个概念在工作中经常用到这些,例如在linux网络IO中涉及到如下模型:

    (1)阻塞式IO

    (2)非阻塞式IO

    (3)IO多路复用

    (4)信号驱动IO

    (5)异步IO

    在知乎上面看到一些解释如下:

    截图如下:

    3、总结

      

      同步和异步针对应用程序来,关注的是程序中间的协作关系;阻塞与非阻塞更关注的是单个进程的执行状态。

    同步:执行一个操作之后,等待结果,然后才继续执行后续的操作。

    异步:执行一个操作后,可以去执行其他的操作,然后等待通知再回来执行刚才没执行完的操作。

    阻塞:进程给CPU传达一个任务之后,一直等待CPU处理完成,然后才执行后面的操作。

    非阻塞:进程给CPU传达任我后,继续处理后续的操作,隔断时间再来询问之前的操作是否完成。这样的过程其实也叫轮询。

       阻塞、非阻塞、多路IO复用,都是同步IO,异步必定是非阻塞的,所以不存在异步阻塞和异步非阻塞的说法。真正的异步IO需要CPU的深度参与。换句话说,只有用户线程在操作IO的时候根本不去考虑IO的执行全部都交给CPU去完成,而自己只等待一个完成信号的时候,才是真正的异步IO。所以,拉一个子线程去轮询、去死循环,或者使用select、poll、epool,都不是异步。

    参考网址:

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

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

    http://www.smithfox.com/?e=191

    https://zhuanlan.zhihu.com/p/21416728

    http://blog.csdn.net/dinglang_2009/article/details/50461697

    展开全文
  • 面试问题什么是异步非阻塞

    千次阅读 2017-06-11 23:59:42
    一、同步与异步 同步/异步, 它们是消息的通知机制 1. 概念解释 A. 同步 所谓同步,就是在发出一个功能调用时,在没有得到结果之前,该调用就不返回。 按照这个定义,其实绝大多数函数都是同步调用(例如sin...
    一、同步与异步
    同步/异步, 它们是消息的通知机制

    1. 概念解释
    A. 同步
    所谓同步,就是在发出一个功能调用时,在没有得到结果之前,该调用就不返回。

    按照这个定义,其实绝大多数函数都是同步调用(例如sin isdigit等)。
    但是一般而言,我们在说同步、异步的时候,特指那些需要其他部件协作或者需要一定时间完成的任务。
    最常见的例子就是 SendMessage。
    该函数发送一个消息给某个窗口,在对方处理完消息之前,这个函数不返回。
    当对方处理完毕以后,该函数才把消息处理函数所返回的值返回给调用者。


    B. 异步
    异步的概念和同步相对。
    当一个异步过程调用发出后,调用者不会立刻得到结果。
    实际处理这个调用的部件是在调用发出后,
    通过状态、通知来通知调用者,或通过回调函数处理这个调用。

    以 Socket为例,
    当一个客户端通过调用 Connect函数发出一个连接请求后,调用者线程不用等待结果,可立刻继续向下运行。
    当连接真正建立起来以后,socket底层会发送一个消息通知该对象。

    C. 三种返回结果途径 
    执行部件和调用者可以通过三种途径返回结果:
    a.   状态、
    b.   通知、
    c.   回调函数。

    可以使用哪一种依赖于执行部件的实现,除非执行部件提供多种选择,否则不受调用者控制。

    a. 如果执行部件用状态来通知,
        那么调用者就需要每隔一定时间检查一次,效率就很低
        有些初学多线程编程的人,总喜欢用一个循环去检查某个变量的值,这其实是一种很严重的错误。

    b. 如果是使用通知的方式,
        效率则很高,因为执行部件几乎不需要做额外的操作。

    c. 至于回调函数,
        和通知没太多区别。


    2. 举例说明
    理解这两个概念,可以用去银行办理业务(可以取钱,也可以存钱)来比喻:
    当到银行后,
    .可以去ATM机前排队等候                                -- (排队等候)就是同步等待消息
    .可以去大厅拿号,等到排到我的号时,
     柜台的人会通知我轮到我去办理业务.              -- (等待别人通知)就是异步等待消息.

    在异步消息通知机制中,
    等待消息者(在这个例子中就是等待办理业务的人)往往注册一个回调机制,
    在所等待的事件被触发时由触发机制(在这里是柜台的人)通过某种机制(在这里是写在小纸条上的号码)
    找到等待该事件的人.

    在select/poll 等IO 多路复用机制中就是fd,
    当消息被触发时,触发机制通过fd 找到处理该fd的处理函数.

    3. 在实际的程序中,
    同步消息通知机制:就好比简单的read/write 操作,它们需要等待这两个操作成功才能返回;
                      同步, 是由处理消息者自己去等待消息是否被触发;
    异步消息通知机制:类似于select/poll 之类的多路复用IO 操作,
                      当所关注的消息被触发时,由消息触发机制通知触发对消息的处理.
                      异步, 由触发机制来通知处理消息者;


    还是回到上面的例子,
    轮到你办理业务, 这个就是你关注的消息,
    而办理什么业务, 就是对这个消息的处理,
    两者是有区别的.

    而在真实的IO 操作时: 所关注的消息就是     该fd是否可读写,
                         而对消息的处理是     对这个fd 进行读写.

    同步/异步仅仅关注的是如何通知消息,它们对如何处理消息并不关心,
    好比说,银行的人仅仅通知你轮到你办理业务了,
    而办理业务什么业务(存钱还是取钱)他们是不知道的.

    二、阻塞与非阻塞
    阻塞/非阻塞, 它们是程序在等待消息(无所谓同步或者异步)时的状态.

    1. 概念解释
    A. 阻塞
    阻塞调用是指调用结果返回之前,当前线程会被挂起。函数只有在得到结果之后才会返回。
    有人也许会把阻塞调用和同步调用等同起来,实际上他是不同的。
    对于同步调用来说,很多时候当前线程还是激活的,只是从逻辑上当前函数没有返回而已。

    socket接收数据函数recv是一个阻塞调用的例子。
    当socket工作在阻塞模式的时候, 如果没有数据的情况下调用该函数,则当前线程就会被挂起,直到有数据为止。

    B. 非阻塞
    非阻塞和阻塞的概念相对应,指在不能立刻得到结果之前,该函数不会阻塞当前线程,而会立刻返回。

    C. 对象的阻塞模式和阻塞函数调用
    对象是否处于阻塞模式和函数是不是阻塞调用有很强的相关性,但是并不是一一对应的。


    阻塞对象上可以有非阻塞的调用方式,我们可以通过一定的API去轮询状态,
    在适当的时候调用阻塞函数,就可以避免阻塞。
    而对于非阻塞对象,调用特殊的函数也可以进入阻塞调用。函数select就是这样的一个例子。

    2. 举例说明
    继续上面的那个例子,
    不论是排队等待,还是使用号码等待通知,
    如果在这个等待的过程中,
    . 等待者除了等待消息之外不能做其它的事情,那么该机制就是阻塞的,
      表现在程序中,也就是该程序一直阻塞在该函数调用处不能继续往下执行.
    . 相反,有的人喜欢在银行办理这些业务的时候一边打打电话发发短信一边等待,这样的状态就是非阻塞的,
      因为他(等待者)没有阻塞在这个消息通知上,而是一边做自己的事情一边等待.

    三、易混淆的点
    很多人也会把异步和非阻塞混淆,
    因为异步操作一般都不会在真正的IO 操作处被阻塞,
    比如如果用select 函数,当select 返回可读时再去read 一般都不会被阻塞
    就好比当你的号码排到时一般都是在你之前已经没有人了,所以你再去柜台办理业务就不会被阻塞.
    可见,同步/异步与阻塞/非阻塞是两组不同的概念,它们可以共存组合,

    而很多人之所以把同步和阻塞混淆,我想也是因为没有区分这两个概念,
    比如阻塞的read/write 操作中,其实是把消息通知和处理消息结合在了一起,
    在这里所关注的消息就是fd 是否可读/写,而处理消息则是对fd 读/写.
    当我们将这个fd 设置为非阻塞的时候,read/write 操作就不会在等待消息通知这里阻塞,
    如果fd 不可读/写则操作立即返回.


    四、同步/异步与阻塞/非阻塞的组合分析
    _______阻塞____________________非阻塞_____
    同步 | 同步阻塞              同步非阻塞
    异步 | 异步阻塞              异步非阻塞

    同步阻塞形式:
      效率是最低的,
      拿上面的例子来说,就是你专心排队,什么别的事都不做。

      实际程序中
      就是未对fd 设置O_NONBLOCK 标志位的read/write 操作,

    异步阻塞形式:
      如果在银行等待办理业务的人采用的是异步的方式去等待消息被触发,也就是领了一张小纸条,
      假如在这段时间里他不能离开银行做其它的事情,那么很显然,这个人被阻塞在了这个等待的操作上面;


      异步操作是可以被阻塞住的,只不过它不是在处理消息时阻塞,而是在等待消息被触发时被阻塞.
      比如select 函数,
      假如传入的最后一个timeout 参数为NULL,那么如果所关注的事件没有一个被触发,
      程序就会一直阻塞在这个select 调用处.

    同步非阻塞形式:
      实际上是效率低下的,
      想象一下你一边打着电话一边还需要抬头看到底队伍排到你了没有,
      如果把打电话和观察排队的位置看成是程序的两个操作的话,
      这个程序需要在这两种不同的行为之间来回的切换,效率可想而知是低下的;

      很多人会写阻塞的read/write 操作,
      但是别忘了可以对fd 设置O_NONBLOCK 标志位,这样就可以将同步操作变成非阻塞的了;

    异步非阻塞形式:
      效率更高,
      因为打电话是你(等待者)的事情,而通知你则是柜台(消息触发机制)的事情,
      程序没有在两种不同的操作中来回切换.

      比如说,这个人突然发觉自己烟瘾犯了,需要出去抽根烟,
      于是他告诉大堂经理说,排到我这个号码的时候麻烦到外面通知我一下(注册一个回调函数),
      那么他就没有被阻塞在这个等待的操作上面,自然这个就是异步+非阻塞的方式了.

      如果使用异步非阻塞的情况,
      比如aio_*组的操作,当发起一个aio_read 操作时,函数会马上返回不会被阻塞,
      当所关注的事件被触发时会调用之前注册的回调函数进行处理,
    展开全文
  • 阻塞和非阻塞,同步和异步 总结

    千次阅读 2018-05-23 10:44:22
    阻塞和非阻塞,同步和异步1 例子故事:老王烧开水。出场人物:老张,水壶两把(普通水壶,简称水壶;会响的水壶,简称响水壶)。老王想了想,有好几种等待方式1.老王用水壶煮水,并且站在那里,不管水开没开,每隔...
  • 关于同步、异步与阻塞、非阻塞的理解 1、前言  前一段时间出去面试,被问到同步、异步与阻塞、非阻塞的区别。我一时半会没有想出来,作为一个工作三年的人来说,实在很惭愧。我当时理解同步、异步属于两个进程...
  • 异步非阻塞、同步、阻塞 概念

    千次阅读 2018-06-24 19:46:01
    异步 / 同步 在维基百科中的释义是:在计算机编程中,异步,指的是独立于主程序流发生的事件,以及处理该事件的方式。这些可能是“外部”事件,例如信号的到达,或由程序发起的操作,该操作与程序同时/并发的执行...
  • 处理大并发之一 对异步非阻塞的理解

    万次阅读 多人点赞 2013-07-17 21:54:00
    处理大并发中对异步非阻塞的理解  在研究nginx和node.js的时候常会遇到异步、非阻塞等,之前自己也经常使用epoll,对其同步与阻塞,异步与非阻塞有了一定的认识,现对参考资料总结下。  首先讨论下使用事件驱动,...
  • 同步异步阻塞非阻塞杂记

    万次阅读 2017-11-10 12:19:14
    gevent实现的协程是同步非阻塞还是异步非阻塞? gevent是一个使用完全同步编程模型的可扩展的异步I/O框架。 IO是不是阻塞的和协程是没有关系的,python本来就能支持非阻塞IO, 比如在linux只要用API,更改了...
  • 深入理解非阻塞同步IO和非阻塞异步IO

    万次阅读 多人点赞 2016-02-02 16:02:46
    很多人对阻塞 / 非阻塞, 同步 / 异步 的概念理解的不深入,搞不清楚非阻塞异步IO的区别,笼统的认为非阻塞IO就是异步IO。其实区别很大,编程模型完全不同。 阻塞 / 非阻塞描述的是函数,指访问某个函数时是否会...
  • 同步、异步与阻塞与非阻塞的区别

    千次阅读 2018-08-21 19:13:22
    有些文章将这四个作了两两组合,于是就有了:异步阻塞和异步非阻塞,可以明确的说,这完全是牵强之理解,无论<Unix网络编程>一书中所列的I/O模式,还是POSIX标准,都没有提这两个概念。异步就是异步!...
  • 同步与异步  同步与异步是针对应用程序与内核的交互而言的。同步过程中进程触发IO操作并等待或者轮询的去... 应用进程请求I/O操作时做一件事如果不能立即获得返回,需要等待,就是阻塞,否则就可以理解为非阻塞。详
  • 深入了解几种IO模型(阻塞非阻塞,同步异步

    万次阅读 多人点赞 2018-03-12 10:51:37
    一般来说,Linux下系统IO主要就是通过以下几个函数open(),close(),read(),write(),send(),recv(),lseek(),今天就以recv()为例来介绍下IO模型中的同步异步,阻塞非阻塞的区别。先说阻塞与非阻塞的区别,recv()函数...
  • 同步异步+阻塞非阻塞-一述

    万次阅读 2018-07-12 08:28:24
    前言在实际的开发中,我们经常会听到同步,异步,阻塞,非阻塞这些编程概念,每次遇到的时候都会蒙圈,然后就各种查网上似是而非的资料,结果越查越迷糊,大部分文章都千篇一律,没有说到本质上的区别,所以下次再...
  • 写的太好了,必须转载一下。 作者:historyasamirrorIO - 同步,异步,阻塞,非阻塞 (亡羊补牢篇)
  • 理解同步异步与阻塞非阻塞的区别

    千次阅读 2020-02-26 16:21:17
    同步异步与阻塞非阻塞的概念对于很多初学者来说是一个模糊的概念,其实我们的生活中存在着很多同步和异步的例子。 同步和异步关注的是消息通信机制 在计算机领域,同步就是指一个进程在执行某个请求的时候,若该...
  • 在Nginx和fastCGI里面每个请求时一个单独的worker线程,而且在各个服务器里面的请求都是阻塞的,所以有些大批量的复杂逻辑或文本处理会导致请求响应时间很长,这里我们就要考虑让PHP实现异步非阻塞的做法,已达到...
  • 简述同步IO和异步IO的区别

    万次阅读 多人点赞 2018-02-01 11:25:00
    同步: 所谓同步,就是在发出一个功能调用时,在没有得到结果之前,该调用就不返回。也就是必须一件一件事做,等前一...当一个异步过程调用发出后,调用者不能立刻得到结果。实际处理这个调用的部件在完成后,通过状
  • 在最近的一些面试中,跟应聘者聊了比较多关于“同步/异步,阻塞/非阻塞”相关的话题,发现大家对于这些概念的理解都比较模糊,甚至有的同学会反问“他们不就是同一个东西吗?”。所以借着这么一个机会,我想用一些...
  • 同步与异步 转自:https://www.jianshu.com/p/47ee57646369 同步和异步关注的是消息通信机制. 同步异步指的是调用者与被调用者两者之间的关系,而不是经常容易误解的多个被调用者之间的关系。 同步 所谓同步,...
1 2 3 4 5 ... 20
收藏数 148,228
精华内容 59,291
关键字:

异步非阻塞