muduo库作者陈硕老师原话:在处理IO的时候,阻塞和非阻塞都是同步IO,只有使用了特殊的API才是异步IO
如果说的是业务层面上的一个逻辑处理是同步还是异步的时候,那么:
- 同步:A操作等待B操作做完事情后,得到返回值,继续处理
- 异步:A操作告诉B操作它感兴趣的事件以及通知方式,A操作继续执行自己的业务逻辑了;等待B监听到相应事件发生后,B会通知A,A开始相应的数据处理逻辑。
-
**同步阻塞:**比如int size = recv(fd,buf,1024,0),如果数据未就绪,recv阻塞当前线程,当数据就绪(fd的数据缓存区中有数据),并且应用程序花时间将缓存区中的数据搬到用户空间定义的buf后,recv返回
-
**同步非阻塞:**比如int size = recv(fd,buf,1024,0),数据未就绪但是recv依然返回,然后根据recv的返回值进行判断,如果
size==0&&errno = EAGAIN
,那么说明数据还没准备好 -
**异步阻塞:**没有必要,不合理
-
**异步非阻塞:**比如Node.js
模拟面试:阻塞、非阻塞、同步和异步
让你谈谈IO的阻塞与非阻塞,同步与异步(最好是理论+实践举例)
对于一个典型的网络IO调用来说,阻塞与非阻塞,同步与异步都是在描述IO的状态。一个典型的网络IO调用,可以分为两个阶段,即数据准备阶段和数据读写阶段。
我们拿recv()这个系统调用举例, 需要传入的参数主要是sockfd,应用程序缓冲区buf以及buf的大小
-
在数据准备阶段
- 如果sockfd工作在阻塞状态下,那么如果sockfd内核的tcp接收缓冲区中没有数据可读,recv就会阻塞当前的调用线程,如果sockfd工作在非阻塞模式状态下,那么revc就会立即返回,然后我们可以根据recv的返回值去判断IO状态,如果返回值size为-1,说明连接中断;size==0 && size == EAGAIN 表明数据未就绪。
-
数据就绪后,进入数据读写阶段
- 对于IO同步来说, 应用程序需要自己将数据由内核缓冲区搬到buf里来,这期间应用程序无法执行其他事情
- 对于异步IO来说,应用程序首先调用系统提供的异步IO接口,比如Linux平台下的aio_read、aio_write,将sockfd, buf以及通知方式告知于内核,这里的通知方式一般有信号和回调函数两种方式,由内核去将数据搬到buf,这期间应用程序可以去执行其他事情,内核将数据搬完后,内核就会按照事先约定的通知方式去通知应用程序,应用程序就可以直接开始处理数据。(异步IO的调用比同步IO的调用复杂)
当然上面提到的同步与异步是对于系统IO而言,如果说到业务逻辑层面的同步与异步(比如登录注册是同步实现还是异步实现)的话:
- 同步指的是A操作要调用B操作的API接口时,A操作一直等到B操作执行完后,得到返回值,然后继续向下处理
- 异步指的是A操作把自己感兴趣的事件以及通知方式告知于B,A继续执行自己的业务逻辑,等到B监听到相应事件后,再通知A去执行相应的处理逻辑。