同步与异步,阻塞与非阻塞基础

1.同步与异步

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

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

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

2.阻塞与非阻塞

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

阻塞调用:指调用结果返回之前,当前线程会被挂起。调用线程只有在得到结果之后才会返回。

非阻塞调用:指在不能立刻得到结果之前,该调用不会阻塞当前线程。

3.通俗理解,来源网络

老张爱喝茶,废话不说,煮开水。
出场人物:老张,水壶两把(普通水壶,简称水壶;会响的水壶,简称响水壶)。
1 老张把水壶放到火上,立等水开。(同步阻塞)
老张觉得自己有点傻
2 老张把水壶放到火上,去客厅看电视,时不时去厨房看看水开没有。(同步非阻塞)
老张还是觉得自己有点傻,于是变高端了,买了把会响笛的那种水壶。水开之后,能大声发出嘀~~~~的噪音。
3 老张把响水壶放到火上,立等水开。(异步阻塞)
老张觉得这样傻等意义不大
4 老张把响水壶放到火上,去客厅看电视,水壶响之前不再去看它了,响了再去拿壶。(异步非阻塞)
老张觉得自己聪明了。

所谓同步异步,只是对于水壶而言。
普通水壶,同步;响水壶,异步。
虽然都能干活,但响水壶可以在自己完工之后,提示老张水开了。这是普通水壶所不能及的。
同步只能让调用者去轮询自己(情况2中),造成老张效率的低下。

所谓阻塞非阻塞,仅仅对于老张而言。
立等的老张,阻塞;看电视的老张,非阻塞。
情况1和情况3中老张就是阻塞的,媳妇喊他都不知道。虽然3中响水壶是异步的,可对于立等的老张没有太大的意义。

所以一般异步是配合非阻塞使用的,这样才能发挥异步的效用。

在处理 IO 的时候,阻塞和非阻塞都是同步 IO。只有使用了特殊的 API 才是异步 IO。

几种常见的网络编程IO模型

阻塞式I/O模型:默认情况下,所有套接字都是阻塞的。怎么理解?先理解这么个流程,一个输入操作通常包括两个不同阶段:

(1)等待数据准备好;
(2)从内核向进程复制数据。

对于一个套接字上的输入操作,第一步通常涉及等待数据从网络中到达。当所有等待分组到达时,它被复制到内核中的某个缓冲区。第二步就是把数据从内核缓冲区复制到应用程序缓冲区。

非阻塞式I/O: 以下这句话很重要:进程把一个套接字设置成非阻塞是在通知内核,当所请求的I/O操作非得把本进程投入睡眠才能完成时,不要把进程投入睡眠,而是返回一个错误。看看非阻塞的套接字的recvfrom操作,可以看出recvfrom总是立即返回。

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

信号驱动式I/O:用的很少。

异步I/O:这类函数的工作机制是告知内核启动某个操作,并让内核在整个操作(包括将数据从内核拷贝到用户空间)完成后通知我们。

其实前四种I/O模型都是同步I/O操作,他们的区别在于第一阶段,而他们的第二阶段是一样的:在数据从内核复制到应用缓冲区期间(用户空间),进程阻塞于recvfrom调用。相反,异步I/O模型在这两个阶段都要处理。

linux 下tcp socket为例:

阻塞就是 recv/read的时候 socket接收缓冲区要是有数据就读, 没数据我就一直睡觉赖着不走,直到有数据来了读完我才走。send/write的时候,要是发送缓冲区满了,没有空间继续发送了我也一直睡觉赖着不走,直到发送缓冲区腾出足够的空间让我把数据全部塞到发送缓冲区里我才走。(当然如果你通过setsockopt设置了读写超时,超时时间到了还是会返回-1和EAGAIN,不再睡觉等待)
非阻塞就是recv/read的时候,要是接收缓冲区有数据我就读完,没有数据我直接带着返回的-1和EGAIN走人,绝不睡觉等待耽误时间。write/send的时候, 要是发送缓冲区有足够的空间,就立刻把数据塞到发送缓冲区去,然后走人,如果发送缓存区满了,空间不足,那直接带着返回的-1和EAGAIN走人。

至于IO多路复用,首先要理解的是,操作系统为你提供了一个功能,当你的某个socket接收缓存区有数据可读,或者发送缓冲区有空间可写的时候,它可以给你一个通知。这样当配合非阻塞的socket使用时,只有当系统通知我哪个描述符可读了,我才去执行read操作,可以保证每次read都能读到有效数据而不做纯返回-1和EAGAIN的无用功。写操作类似。操作系统的这个功能通过select/poll/epoll之类的系统调用函数来使用,这些函数都可以同时监视多个描述符的读写就绪状况,这样,多个描述符的I/O操作都能在一个线程内完成,这就叫I/O多路复用,这里的“复用”指的是复用同一个线程。

至于事件驱动,其实是I/O多路复用的一个另外的称呼。

至于异步同步,我们常见的linux下的网络编程模型大部分都是同步io,以读操作为例,本质上都是需要用户调用read/recv去从内核缓冲区把数据读完再处理业务逻辑。异步io则是内核已经把数据读好了,用户直接处理逻辑。异步IO在linux下一般是用aio库。

层次进行讨论:

同步、异步、阻塞、非阻塞,是分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.zhihu.com/question/19732473

时间: 2024-07-30 13:45:18

同步与异步,阻塞与非阻塞基础的相关文章

IO多路复用,同步,异步,阻塞和非阻塞 区别(转)

转自:http://www.cnblogs.com/aspirant/p/6877350.html?utm_source=itdadao&utm_medium=referral 一.什么是socket?什么是I/O操作? 我们都知道unix(like)世界里,一切皆文件,而文件是什么呢?文件就是一串二进制流而已,不管socket,还是FIFO.管道.终端,对我们来说,一切都是文件,一切都是流.在信息 交换的过程中,我们都是对这些流进行数据的收发操作,简称为I/O操作(input and outp

同步、异步、互斥、信号量、阻塞、非阻塞

(1)临界资源 在操作系统中,进程是占有资源的最小单位(线程可以访问其所在进程内的所有资源,但线程本身并不占有资源或仅仅占有一点必须资源).但对于某些资源来说,其在同一时间只能被一个进程所占用.这些一次只能被一个进程所占用的资源就是所谓的临界资源. (2)同步.互斥        相交进程之间的关系主要有两种:同步与互斥(一定要记住:不是同步和异步).所谓互斥,是指散布在不同进程之间的若干程序片断,当某个进程运行其中一个程序片段时,其它进程就不能运行它 们之中的任一程序片段,只能等到该进程运行完

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

阻塞.非阻塞.同步.异步IO http://www.cnblogs.com/yunxitalk/p/9031306.html 介绍 在谈及网络IO的时候总避不开阻塞.非阻塞.同步.异步.IO多路复用.select.poll.epoll等这几个词语.在面试的时候也会被经常问到这几个的区别.本文就来讲一下这几个词语的含义.区别以及使用方式. Unix网络编程一书中作者给出了五种IO模型: 1.BlockingIO - 阻塞IO 2.NoneBlockingIO - 非阻塞IO 3.IO multip

(转)IO复用,AIO,BIO,NIO,同步,异步,阻塞和非阻塞 区别

本文来自:https://www.cnblogs.com/aspirant/p/6877350.html?utm_source=itdadao&utm_medium=referral,非常感谢. 如果面试问到IO操作,这篇文章提到的问题,基本是必问,百度的面试官问我三个问题 (1)什么是NIO(Non-blocked IO),AIO,BIO (2) java IO 与 NIO(New IO)的区别 (3)select 与 epoll,poll区别 我胡乱说了一气,自己边说边觉得完蛋了.果然,二面

一文读懂阻塞、非阻塞、同步、异步IO

原文:一文读懂阻塞.非阻塞.同步.异步IO 介绍 在谈及网络IO的时候总避不开阻塞.非阻塞.同步.异步.IO多路复用.select.poll.epoll等这几个词语.在面试的时候也会被经常问到这几个的区别.本文就来讲一下这几个词语的含义.区别以及使用方式.Unix网络编程一书中作者给出了五种IO模型:1.BlockingIO - 阻塞IO2.NoneBlockingIO - 非阻塞IO3.IO multiplexing - IO多路复用4.signal driven IO - 信号驱动IO5.a

同步与异步、阻塞与非阻塞

"阻塞"与"非阻塞"与"同步"与"异步"不能简单的从字面理解,提供一个从分布式系统角度的回答.1.同步与异步同步和异步关注的是消息通信机制 (synchronous communication/ asynchronous communication)所谓同步,就是在发出一个*调用*时,在没有得到结果之前,该*调用*就不返回.但是一旦调用返回,就得到返回值了.换句话说,就是由*调用者*主动等待这个*调用*的结果. 而异步则是相反

阻塞、非阻塞、同步、异步

同步和异步关注的是消息通信机制. 同步 调用者主动等待调用结果返回,没有得到结果之前,该调用不返回. 异步 调用者不必马上等待返回结果,执行部件通过通知.状态或回调函数来返回结果给调用者. 阻塞和非阻塞关注的是程序等待调用结果的状态. 阻塞 调用返回之前,当前线程挂起.调用线程只有等待结果之后才返回. 非阻塞 它不会阻塞当前线程.

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

1. 概念理解 在进行网络编程时,我们常常见到同步(Sync)/异步(Async),阻塞(Block)/非阻塞(Unblock)四种调用方式: 同步/异步主要针对C端: 同步:      所谓同步,就是在c端发出一个功能调用时,在没有得到结果之前,该调用就不返回.也就是必须一件一件事做,等前一件做完了才能做下一件事. 例如普通B/S模式(同步):提交请求->等待服务器处理->处理完毕返回 这个期间客户端浏览器不能干任何事 异步:      异步的概念和同步相对.当c端一个异步过程调用发出后,调

同步和异步、阻塞和非阻塞

首先说明我对这些概念也不是很清楚,以下内容是我做的一些理事. 同步和异步.阻塞和非阻塞这是两组概念,说的是不同的事情,同步和阻塞没有必然的联系,异步和非阻塞也没有必然的联系.同步和异步是只跟IO操作过程中进程的状态变化有关.阻塞和非阻塞就是进程的两种状态.比如你去银行,排除的话就是一种同步的方式,叫号的话就是异步的方式.排队必须自己看着什么时候轮到自己,而叫号则不必,轮到你的时候会触发一个事件,或者说你会收到一个信号,别人会叫你.不管是排除还是叫号,如果你在等待的过程中不能做其他事情,那就是阻塞