非阻塞和异步有差别吗?阻塞、非阻塞、同步和异步概念总结

阻塞与非阻塞

如阻塞、非阻塞字面意思一般,我们很容易得到结论就是:阻塞就是调用该方法后会阻塞当前线程,直到方法返回,而非阻塞则相反,调用方法后不会阻塞当前线程,会立即返回结果,比如如果当前还没有任何数据拷贝到内核缓冲区,但又由于需要立即返回结果,那么read函数就会返回-1,以告知用户这次调用读取不到任何数据。

但其实这个结论并不严谨,理由如下:

这里有三个概念需要注意:对应的硬件内核缓冲区用户缓冲区。比如对于read函数,从对应硬件拷贝数据到内核缓冲区,从内核缓冲区拷贝数据到用户缓冲区,这两个步骤都需要等待。阻塞和非阻塞针对的都是第一个步骤而言的,对于第二个步骤,不论是阻塞IO还是非阻塞IO,当前线程都会进入阻塞状态。这一点很重要,是后面区分非阻塞和异步的关键。

由上可知,阻塞和非阻塞IO的阻塞主要是对于第一个步骤进行区分的,和我们理解的阻塞与非阻塞概念不完全一致。

同步与异步

同步指的是发起调用后,没返回结果前不会返回,而异步指的是发起调用后立即返回结果。从这个角度来看,非阻塞IO就不能算是异步操作了

多路复用IO为什么算非阻塞而非异步

我们知道多路复用IO是同时监听多个socket状态。比如有一个socket已经可读取数据时,我们就可以调用read方法去获得数据,但是这里的可读取是指有数据到了内核缓冲区,我们去调用read还是需要等待其拷贝到用户缓冲区的,所以多路复用IO不能算作异步。

这里强烈推荐读一下这篇文章,详细阐述了多路复用IO的概念:IO多路复用到底是不是异步的?

异步的相关操作

上面说了这么多,都没有讲到异步相关的操作。其实异步操作并不复杂,如果操作系统在其将数据完全拷贝至用户缓冲区时再通知我们,那么就等于实现了异步。而借助系统提供的相关的API,我们就能完成这个操作,让这些IO操作都交给操作系统去完成。

一些题外话

由上面的讨论我们不难发现,由于IO操作的费时,我们总希望操作系统能全权负责这些操作,毕竟每次调用read函数都是一次系统调用,而系统调用涉及到由用户态转到内核态,有上下文切换的开销,所以我们希望一次系统调用最好能把相关的操作全部完成,避免后续还需要反复系统调用,让程序变慢。

参考链接

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

Linux IO模式及 select、poll、epoll详解

猜你喜欢

转载自blog.csdn.net/weixin_55658418/article/details/129483301