同步/异步、阻塞/非阻塞、IO复用

 简单来说,在应用中,阻塞、非阻塞和IO复用都是同步,异步是非阻塞的(严格来说异步也有阻塞的)。

同步/异步

  关注的是一种消息通信的机制,关注的是手段与行动,表示一种协作方式,从全局或者更高的角度来看待“进程之间合作方式”的

同步:

  总是按照“甲方请求一次,乙方应答一次”这样的有序序列处理业务,只有当“一次请求一次应答”的过程结束才可以发生下一次的“一次请求一次应答”,那么就说他们采用的是同步。(同步IO中,对同一个描述符的操作必须是有序的)也就是必须一件一件事做,等前一件做完了才能做下一件事。

异步:

  如果甲方只要有需要,就会发送请求,不管上次请求有没有得到乙方应答。而乙方只要甲方有请求就会接受,不是等这次请求处理完毕再接受甲方新请求。这样请求应答分开的序列,就可以认为是异步。异步情况下,请求和应答不需要一致进行,可能甲方后请求的业务,却先得到乙方的应答。同步是线性的,而异步可以认为是并发的。( 异步IO中,异步IO可以允许多方同时对同一个描述符发送IO请求,或者一次发多个请求,当然有机制保证如何区分这些请求
  实际处理这个调用的部件在完成后,通过状态、通知和回调来通知调用者。

阻塞/非阻塞

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

  阻塞调用是指调用结果返回之前,当前线程会被挂起(线程进入非可执行状态,在这个状态下,cpu不会给线程分配时间片,即线程暂停运行)。函数只有在得到结果之后才会返回。

     有人也许会把阻塞调用和同步调用等同起来,实际上他是不同的。对于同步调用来说,很多时候当前线程还是激活的,只是从逻辑上当前函数没有返回而已。 例如,我们在socket中调用recv函数,如果缓冲区中没有数据,这个函数就会一直等待,直到有数据才返回。而此时,当前线程还会继续处理各种各样的消息。

非阻塞:

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

I/O多路复用:
  虽然I/O多路复用的函数也是阻塞的,但是其与以上两种还是有不同的,I/O多路复用是阻塞在select,epoll这样的系统调用之上,而没有阻塞在真正的I/O系统调用如recvfrom之上。(可算非阻塞?)
 
 

总结1:

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

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

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

 

总结2:

  同步异步针对的是两个事情之间的关系,这种关系与拓扑结构中的先后关系类似类,如果两件事情之间存在拓扑关系,便是同步关系;如果没有时序先后的关联或相互依赖,则是异步关系。而阻塞非阻塞针对的是发起任务的人(线程)的状态问题。在I/O中,同步异步涉及的两件事情是:消息响应和消息处理,I/O模型中这两个事务之间的拓扑关系决定了模型是同步还是异步的。而在消息响应的过程中,发出I/O请求的线程所处的状态决定了模型是阻塞还是非阻塞的。

参考:

怎样理解阻塞非阻塞与同步异步的区别? - 知乎

socket阻塞与非阻塞,同步与异步、I/O模型,select与poll、epoll比较

 
--------------分割线----------------
知乎用户@ 银月游侠
从三个层次理解这个关系

这几个概念,上面不少答案已经写得很清楚了。这里我结合自己的理解,简单地聊一下为什么这几个概念容易混淆。如果有错误之处,恳请批评指正。

我认为同步、异步、阻塞、非阻塞,是分3个层次的:
  1. CPU层次;
  2. 线程层次;
  3. 程序员感知层次。

这几个概念之所以容易混淆,是因为没有分清楚是在哪个层次进行讨论。

CPU层次
在CPU层次,或者说操作系统进行IO和任务调度的层次,现代操作系统通常使用异步非阻塞方式进行IO(有少部分IO可能会使用同步非阻塞轮询),即发出IO请求之后,并不等待IO操作完成,而是继续执行下面的指令(非阻塞),IO操作和CPU指令互不干扰(异步),最后通过中断的方式来通知IO操作完成结果。

线程层次
在线程层次,或者说操作系统调度单元的层次,操作系统为了减轻程序员的思考负担,将底层的异步非阻塞的IO方式进行封装,把相关系统调用(如read,write等)以同步的方式展现出来。然而,同步阻塞的IO会使线程挂起,同步非阻塞的IO会消耗CPU资源在轮询上。为了解决这一问题,就有3种思路:
  1. 多线程(同步阻塞);
  2. IO多路复用(select,poll,epoll)(同步非阻塞,严格地来讲,是把阻塞点改变了位置);
  3. 直接暴露出异步的IO接口,如kernel-aio和IOCP(异步非阻塞)。

程序员感知层次
在Linux中,上面提到的第2种思路用得比较广泛,也是比较理想的解决方案。然而,直接使用select之类的接口,依然比较复杂,所以各种库和框架百花齐放,都试图对IO多路复用进行封装。此时,库和框架提供的API又可以选择是以同步的方式还是异步的方式来展现。如python的asyncio库中,就通过协程,提供了同步阻塞式的API;如node.js中,就通过回调函数,提供了异步非阻塞式的API。

总结
因此,我们在讨论同步、异步、阻塞、非阻塞时,必须先明确是在哪个层次进行讨论。比如node.js,我们可以说她在程序员感知层次提供了异步非阻塞的API,也可以说在Linux下,她在线程层次以同步非阻塞的epoll来实现。
 
 
 
 
 
 

转载于:https://www.cnblogs.com/bw13/p/6410137.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值