百科问答小站 logo
百科问答小站 font logo



怎样理解阻塞非阻塞与同步异步的区别? 第1页

  

user avatar   xiao-xiao-99-94 网友的相关建议: 
      

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 中的上下文(程序计数器, 寄存器)到 PCBi (操作系统分配给进程的一个内存块)中。
  3. 从 PCBj 取出进程 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.




从上面的过程可以看出,用户级支持线程(User-Supported Threads)的解决方案基于非阻塞IO系统调用( non-blocking system call) , 且是一种基于操作系统内核事件通知(event-driven)的解决方案, 该方案可以降低系统处理并发请求时的进程切换开销。 基于这个方案, 可以引申到更为宽泛的 event-driven progreamming 话题上。 但是这里就不作赘述了。

总结:

  1. 阻塞/非阻塞, 同步/异步的概念要注意讨论的上下文:
  • 在进程通信层面, 阻塞/非阻塞, 同步/异步基本是同义词, 但是需要注意区分讨论的对象是发送方还是接收方。
  • 发送方阻塞/非阻塞(同步/异步)和接收方的阻塞/非阻塞(同步/异步) 是互不影响的。
  • 在 IO 系统调用层面( IO system call )层面, 非阻塞 IO 系统调用 异步 IO 系统调用存在着一定的差别, 它们都不会阻塞进程, 但是返回结果的方式和内容有所差别, 但是都属于非阻塞系统调用( non-blocing system call )

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


user avatar   Ivony 网友的相关建议: 
      

一个异步的过程可以通过阻塞线程(执行绪)来进行同步调用。


user avatar   svjoke 网友的相关建议: 
      

我个人并不是很看好。

html5,js以及类似的技术替代原生大家喊了很久了,就是大热的react native目前看来也依然很不完善。微信的应用应该都是运行在腾讯浏览器的X5内核里,这东西怎么样大家心里也都有数。我感觉还是只能做一些低交互的应用,大概也就是比网页快捷方式高一级别,要利用os的炫酷特性,原生还是跑不掉,而且目前原生开发很成熟了,框架库很多,门槛也很低。

对于不用下app省空间我不是很理解,只不过是把app浪费的空间挪动到微信里而已。

微信所倡导的用完即走的理念也只有腾讯有资本装b才会这么说,其它公司无论如果始终还是会想办法更多的占用用户的时间。

腾讯现在原本就掌握了渠道,现在连app的审核等生杀大权也都掌握,你说苹果恶心,但他起码还勉强算公平,而腾讯可以随便打着为了用户(和你妈说为了你好)进行系统抖动,非腾讯系全都会抖,想怎么搞你怎么搞你。


结局都是类似的,中小型公司都很激动,以为有了小应用他们就有了腾讯爸爸的几亿用户,这种幻觉很美好,但他们可能会面临更加惨烈的竞争,变成临时解决用户欲望的千斤顶,以及腾讯渠道那可怕的推广分成费用。大公司肯定都很不情愿的跟进,又没办法,估计会简单开发一些应用,然而尽可能的往自己原生的app上导入,心态很微妙,不过短期内肯定会先爆发一波星座血型算命起名你的前世今生颜值计算能活多少岁等一些QQ空间喜闻乐见的低质量辣鸡应用,目前也不知道腾讯审核时是否会做一些限制。

微信也许已经不是聊天软件了,我朋友偶尔用了一下QQ,惊叹的说,QQ真好用呀,聊天记录都能自动存下来! 微信当初也许吸引大家的是我们只想要一个广聊天的QQ,现在已经要变成微信os了,是不是以后也要走和当年QQ一样的路?整个腾讯系全压在这款app中? 我不知道,在集团利益,业绩增长的车轮下,什么张小龙王小龙,什么鬼的用户体验,什么产品经理说不的坚持,有多少碾碎多少。

仅是个人一点感悟和粗浅看法,不太对请见谅


user avatar   giantchen 网友的相关建议: 
      

我是一名基层派出所民警。

可以说当今中国警察普遍羡慕美国警察可以采取暴力手段绝对的镇压不法分子。

但是,不得不说,这次这位美国警察,太过分了,不仅是过分,而且我的理解是那已经构成了犯罪行为。那黑人已经制服了就可以正常上拷带走了,没必要一直压着脖子压那么长时间。没能置身其中不知现场那美国警察的所思所想,反正我个人挺不理解他为啥那样干的。

只能说无论什么地方,无论什么行业,只要是人的社会,都有像样的也有操蛋的吧。

_________此处为分割线 _________

以下为统一答复评论中有些人质疑的我所讲的羡慕二字。

能够出现这种质疑在我料想之中,因为中国警察也有过过分的时代,据我所知就是在七十八十九十年代,就如同地痞流氓,看谁不顺眼就能打谁对老百姓而言没王法可讲,那时候的警察说好听点可以说是威风凛凛说难听点儿是横行霸道。

但我想表明的是,时过境迁,现在的中国警察无论是受舆论约束还是因为法治社会建设制度规范都已经变得逐步文明与规范起来,起码我认为从我们现在开始从公安司法院校毕业参加公务员考试考进来的新一代警察已经具备新的面目,当然不可否认的是在这个行业内目前仍然存有历史的顽疾,仍然存在着臭虫,但我已经讲过无论什么行业都有操蛋的吧,这是个人问题,不是群体问题。相比之下,拍拍良心看,现在的整个警察队伍比照曾经确实过分的年代是不是已经是天地之别,问问曾经真正挨过曾经年代老警察欺负的中老年人就知道了。

为何会说起羡慕,因为警察每天面对的人群,大多是三教九流之辈,没有武力加身,很多事情在处理上警察显得软弱无能,说白了,好人谁没事儿上派出所转悠啊都忙着自己的生活呢,警察打人这句话,我们常常听到,但是但凡有点脑袋的人都能想明白,警察会闲着没事儿干把那在家里消停待着的遵纪守法的人抓起来暴揍一顿吗?

以上言辞不免更会有人质疑,请允许我解释,武力,当然不可滥用,我所说的羡慕不是羡慕美国警察的随意滥用武力,而是在合法范围内准许在对方不听从警察指令时动用武力,现在确实有人民警察法赋予了相关权力,但实践中现在的中国警察并不能或者说不敢执行人民警察法里的所有权力。拿防疫工作举例,卡口的工作人员在让出入的人员扫码登记时,就会有不愿意配合的人,然而这些不愿意配合的人可会知道工作人员的所做所为是为了整个社区的稳定安全,因为这整个社区包括了这名不愿意配合的人啊,在这个时候是否应当对其进行武力控制来保障其他居民的安全呢。同理,警察盘查也好,调查也好,总会有那些不愿意配合的人,自我感觉良好认为自己没问题所以警察不必要对其进行盘查所以就不配合,而警察当看到对方不配合时会以什么视角审视,难道要说谢谢您的不配合吗,万一这不愿配合的人真背着案子呢,那便是对更多的人民群众的不负责任。因此,我要说,民众的素质如果真正达到了人人互相敬重路不拾遗夜不闭户的文明程度,要求警察绝对文明不要有暴力举动,一点问题没有,一味强调了警察不该暴力执法而分毫不过问被执法对象自身是否存在问题,是不是看问题的角度些微的片面了些。

请注意,我说羡慕里的那句话尾巴实际已经表明了,羡慕的是暴力手段对不法分子的镇压,可不是对遵纪守法的百姓也要肆意妄为。例如像给群众办个身份证居住证之类的业务,警察当然应该热心服务。但当面对泼皮无赖时,还要笑脸相迎,得来的只有蹬鼻子上脸,警察都不怕了,您们认为这些无赖还有谁管得了。

列位存有异议的同志们,谢谢您们的教诲。言辞中犀利的同志们,谢谢您们的敦促。

让我知道当警察,需要吾日三省吾身。

还想要质疑甚或是骂的您们,若是能让您舒服,骂两句无妨。我不算您辱骂警察。不过是,道不同不相为谋罢了吧。

_____分割线

2020年6月5日22:53 出警在路上




  

相关话题

  如今只使用TCP协议开发 实时多人在线网络游戏 可行吗? 
  C#的async和await底层是怎么做到的? 
  C#的async和await底层是怎么做到的? 
  阻塞/非阻塞、同步/异步还有并发、并行、分布式这些概念的区别是什么?分别适用于哪些编程场景? 
  Task.Run(Foo)和FooAsync()有何区别? 
  阻塞/非阻塞、同步/异步还有并发、并行、分布式这些概念的区别是什么?分别适用于哪些编程场景? 
  Http 协议中为什么只通过Content-Type控制请求体的编码,没有设计Header请求头编码? 
  为什么 Node.js 这么火,而同样异步模式 Python 框架 Twisted 却十几年一直不温不火? 
  有哪些关于C++高性能服务器开发的高质量博客? 
  如何扎实系统地学好后端开发(Linux 环境下)?细分方向有哪些?可否推荐一些好的开源项目? 

前一个讨论
Facebook 的人工智能实验室 (FAIR) 有哪些厉害的大牛和技术积累?
下一个讨论
pytorch 分布式计算 你们都遇到过哪些 坑/bug?





© 2024-11-22 - tinynew.org. All Rights Reserved.
© 2024-11-22 - tinynew.org. 保留所有权利