3

linux IO —— 理解阻塞/非阻塞、同步/异步

 1 year ago
source link: https://www.zoucz.com/blog/2022/05/30/61cc9780-dfdc-11ec-9fe7-534bbf9f369d/
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.

linux IO —— 理解阻塞/非阻塞、同步/异步

作者: 邹成卓 2022-05-30 13:50:16 分类: linux

标签: linux

评论数:

接上篇 linux IO —— 多路复用(select/poll/epoll) 我要说话

阻塞/非阻塞、同步/异步,是两对非常容易弄混淆的名词。不光可能由于对原理的理解不到位而造成混淆;在理解原理后,也有可能因为词义的原因造成混淆,即大家的理解都是没问题的,只是描述的时候出了偏差。 我要说话

网上分析这两个概念的文章非常多,这里也记录一下我的理解吧,如果理解有误,麻烦轻喷指出…我要说话

阻塞/非阻塞、同步/异步,描述的都是 一段程序 在进程(也可能是线程,下面统一用进程指代)内的执行状态。 我要说话

这里加粗的部分值得注意,一个是描述对象,当我们讨论一个状态时,一定要指明被描述的目标对象,否则可能鸡同鸭讲,大家各说各的。 我要说话

例如,问:一段使用epoll做网络IO的代码 是阻塞的还是非阻塞的,是同步的还是异步的?我认为这样的问题是没有意义的,因为描述的对象不够具体,针对不同的对象也有不同的答案。 我要说话

阻塞与同步

从操作系统的角度来讲,IO操作是阻塞的,还是非阻塞的,指的是IO操作会不会阻止 CPU 执行当前进程。 我要说话

例如阻塞read:当没有可读数据,read操作无法完成时,该操作会将当前进程从CPU的工作队列中移除,不再执行当前进程的任务,直到有数据到来,我们认为它是阻塞的。 我要说话

image.png
我要说话

如上图,一次阻塞read的过程,应用进程从调用read,到开始处理数据,中间经历了两个阶段,一个是“等待数据”,另一个是“数据从内核到用户”。这两个阶段中,操作系统会将进程移出CPU的工作队列,阻止CPU执行当前进程的任务,我们称这个read操作是“阻塞”的。 我要说话

首先说明,“阻塞当前进程”这个说法是比较口语化的,非官方的说法,但是很多人沟通的时候喜欢这样描述,所以单独提出来下。 我要说话

“阻塞当前进程”即进程在某 一段时间 内持续做这件事情,不能去做其它事情。 我要说话

例如上面图中的 “等待数据”,“数据从内核到用户”,这两个时间段内,进程都不能去做其它事情,很多时候这种状态会被描述为,进程被阻塞住了。 我要说话

对于一个线程而言,其实有一种更准确的说法:这个操作是 同步 的。如果将这个阻塞的过程放到另一个线程去执行,那么它就不会占用当前线程的时间了,就应该称它为异步操作。 我要说话

同步操作还有,sleep、互斥锁等待、while true/自旋锁等待,等等。它们的特点都是会占用进程一段时间,不能做其它事情。但是前两个操作,进程是会进入阻塞状态的,而后两个,则不会进入阻塞状态,所以前面关于“阻塞当前进程”的口语化的说法,是不准确的,分歧点 就在这里。 我要说话

所以我们能得出结论:对于同一个进程(线程),阻塞操作一定是同步的,同步操作不一定是阻塞的。 我要说话

非阻塞与异步

非阻塞IO

前面分析了阻塞IO的流程,下面是非阻塞IO的流程。 我要说话

image.png
我要说话

非阻塞IO的场景下,“等待数据”阶段,不会再让进程进入阻塞状态,而是定期的去调用read,如果没有数据,则瞬间返回结果 EWOULDBLOCK,不占用 一段时间,这样CPU就可以去做其它事情(例如操作另一个IO,我们称这个read操作是“异步”的。 我要说话

但是,这里有一点要注意的是,“数据从内核到用户”,进程还是需要等待一会儿CPU将数据从内核缓冲区拷贝到用户缓冲区。这个过程也是非阻塞的,不会让出CPU,但是在此期间进程也是无法执行其它工作的,也就是“同步”的。 我要说话

非阻塞与异步

从上面的图中可以看到,非阻塞IO分为两个阶段,一个是非阻塞轮询阶段,这个阶段瞬间返回不占用“一段时间”,进程在此期间还可以去做其它事情,是“异步”的;而在第二个复制数据的阶段,这个阶段进程也是非阻塞状态,但是需要等待数据拷贝完成,会占用“一段时间”,尽管这个时间非常短,我们也认为这个过程是“同步”的。 我要说话

在轮询阶段,如果我们对单个fd使用 while true,去不断轮询结果,这样就会持续占用CPU时间,即使整个操作都是非阻塞的,进程也无法再执行其它工作了,这期间的操作也认为是“同步”的。实际上很少会这样做,都是结合多路复用来将等待的过程异步化的。 我要说话

那么真正的异步IO模型是什么样的呢? 我要说话

image.png
我要说话

如图,和非阻塞IO相比,异步IO不再让用户通过多次调用轮询状态了,而是调用io操作后不进入阻塞,立即返回。数据拷贝阶段,也不再等待内核进行拷贝了,而是后续通过信号、事件等方式,告知进程数据已经ready。在通知之前,进程可以做其它的工作,等待期间不占用进程资源。 我要说话

所以我们能得出结论:对于同一个进程(线程),非阻塞操作不一定是异步的,但是异步操作一定是非阻塞的。我要说话

正如第一节“描述对象”中所说,抛开具体的目标对象谈阻塞还是非阻塞,同步还是异步,都是无意义的,可以对下面是几种IO模型分析一下,各个阶段是阻塞的还是非阻塞的,是同步的还是异步的。 我要说话

image.png
我要说话

这个没什么好说的,全程阻塞,全程同步我要说话

非阻塞IO

检查阶段是非阻塞的,异步的;数据拷贝阶段非阻塞等待,同步。 我要说话

IO多路复用

wait阶段阻塞、同步;数据读取阶段由具体的IO操作决定,比如是普通的阻塞/非阻塞IO,在这个阶段都是阻塞的,同步的。我要说话

信号驱动IO

有点像自动检查的非阻塞IO,检查阶段非阻塞,异步;数据读取阶段阻塞,同步。 我要说话

全程非阻塞,异步。我要说话

对于单个进程(线程): 我要说话

特性 同步 异步
阻塞 ①阻塞IO全程②多路复用wait③信号驱动IO拷贝节点 不存在
非阻塞 非阻塞IO拷贝阶段 非阻塞IO等待阶段、异步IO

参考文章: 我要说话

本文链接:https://www.zoucz.com/blog/2022/05/30/61cc9780-dfdc-11ec-9fe7-534bbf9f369d/我要说话

☞ 参与评论我要说话


About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK