同步、异步、阻塞、非阻塞,以及IO模型的理解

本文详细介绍了同步和异步、阻塞和非阻塞的概念,以及它们的不同组合方式。讨论了IO操作中的同步和异步,包括阻塞I/O、非阻塞I/O、I/O多路复用、信号驱动I/O和异步I/O模型,并通过类比总线协议帮助理解。文章最后探讨了各种IO模型的适用场景,强调了在选择IO模型时应考虑的主要因素是IO传输效率和CPU利用率。
摘要由CSDN通过智能技术生成

同步和异步

同步 就是你知道你什么时候在做什么,做完一件事情再做下一件事情,因此主动权在自己手里。比如通过等待或轮询,你在某个时间点总是知道结果是怎样的(有数据还是没数据等)。
异步 就是你不知道什么时候会发生什么。比如你注册了多个回调函数,你不知道什么时候会被调用以及被调用的是哪一个回调函数。

阻塞和非阻塞

阻塞:一个调用过程必须完成才返回。对于IO操作,如果IO没有准备好,读取或者写入等函数将一直等待。
非阻塞:一个调用过程会立即返回,无论结果怎样。对于IO操作,读取或者写入函数总会立即返回一个状态,要么读取成功,要么读取失败(没有数据或被信号中断等)。
看微博上有人(屈春河的微博)说还有部分阻塞:整个调用过程分为C1,C2,…,Cn步,调用者完成C1,…,Cj步后就返回,而不是等待完成整个调用过程。

组合方式

通常有三种组合方式:
同步阻塞:所有动作依次顺序执行。单线程可完成。
同步非阻塞:调用者一般通过轮询方式检测处理是否完成。单线程可完成。
对于IO操作来讲,我们熟悉的select/epoll,即IO多路复用,可以认为属于这种工作方式。不过有人说select/epoll是异步阻塞的方式,这是为啥呢?明明select/epoll过程在用户态看来类似于轮询,而读写过程可以非阻塞的。实际上select/epoll过程是阻塞的,但它的好处是可以同时监听多个fd且可以设置超时,并且利用select/epoll的阻塞换取了读写的非阻塞。
异步非阻塞:Callback模式,注册回调,等待其他线程利用回调执行后续处理。Linux kernel里面有个aio就是异步非阻塞IO,但好像很多坑。

IO操作中的同步和异步

需要再重复一下几种IO模型:
1.阻塞I/O (blocking I/O):recv和recvfrom是阻塞的,即没有数据到来之前本线程不能做其他事情。
2.非阻塞I/O (nonblocking I/O):recv和recvfrom没有数据时也立即返回,但要一直进行recv/recvfrom并轮询返回值,浪费CPU。可以用fcntl来设置非阻塞:
int fcntl(int fd, int cmd, long arg);
例如:
sockfd = socket(AF_INET, SOCK_STREAM, 0);
fcntl(sockfd, F_SETFL, O_NONBLOCK);
3.I/O多路复用 (I/O multiplexing):select/poll/epoll,没数据时会阻塞,有数据的时候返回就可以进行recv了,它和阻塞I/O的区别是可以同时监听多个套接字描述符上的数据,有一个有数据就返回。而阻塞I/O是阻塞在recv那个地方,而且recv的时候已经指定某一个套接字了。
4.信号驱动I/O (signal driven I/O (SIGIO)):通过注册SIGIO的信号处理函数,来监听和接收数据(我没用过)。
5.异步I/O (asynchronous I/O):利用aio机制,设置存放数据的缓存、回调函数以及回调的方式(线程或信号等),并调用aio_read()读数据并立即返回。内核中准备好数据并拷贝完成后,通知用户态去读。

可见,这里并不是按照同步异步和阻塞非阻塞的组合给出的,我们也不必去纠结。但是异步IO模型和其他4种模型的一个显著区别在于:前4种模型最终调用recv去读,读的过程包括数据拷贝并返回状态,交给用户态处理;而异步IO在内核中默默地拷贝数据,记录状态,用户态省去了读操作,而是直接处理数据,这也是aio为什么需要预先分配读缓存的原因。
如果非要套用同步和异步的概念,那我认为是按照re

  • 4
    点赞
  • 13
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值