同步与异步,阻塞与非阻塞,以及这四个名词之间的两两集合,是学习并发编程/网络编程时会遇到的几个重要概念
注:以下IO指的是linux下的I/O
同步与异步:
同步与异步这两个概念,可以从消息的通信机制上来理解
当一个进程需要执行I/O操作时,如果进程需要一直等待操作结果的返回,甚至被挂起,那么这就属于同步的范畴
如果在等待I/O结果返回的过程中,进程可以执行其他代码,那么这就属于异步
比如我要分析一个大小为10G的日志文件,在读取日志文件内容的时候会耗费较长一段时间
如果采用同步操作,那么相关进程会一直等待文件读取完毕,这段时间内CPU会一直处于等待状态
如果采用异步操作,相关进程可以把读取I/O的指令传送给内核,在内核操作I/O的过程中,相关进程可以执行其他代码,比如初始化一些变量,或者一些构造函数,甚至进行其他高计算量的任务
异步的执行效率并不是永远比同步高,因为进程(内核态到用户态)的切换也需要消耗一定的计算资源
所以异步更适合于进程切换需要少,I/O操作时间长的任务.Linux下常用的select/epoll/poll函数就是采用同步模型
阻塞与非阻塞
要注意的一点是,如果一份任务采用异步模型,那么它肯定是非阻塞的,同步模型才需要讨论阻塞与非阻塞
如果等待I/O的过程中,进程挂起,直到内核返回信息说I/O执行完毕,进程才继续执行接下来的代码,那么就属于阻塞
如果在等待I/O过程中,进程没有挂起,可以执行其他操作,但是每隔一段时间得主动去询问内核I/O执行完毕没有,那么就属于非阻塞
同步非阻塞与异步很相像,区别就在于当前进程需不需要去向内核询问I/O执行完毕了没有
I/O多路复用
由于linux下多数I/O都属于同步模型,如果遇到某个I/O执行时间过长时,会导致整个进程都被阻塞住.
(这里有一点需要注意,即便是同步非阻塞模型,在I/O执行完毕拷贝到内存的过程当中,也是属于阻塞的)
为了解决这个问题,人们又提出了I/O多路复用技术,将I/O操作分离开(可以是多个I/O),利用一个线程做轮询操作,当哪个I/O操作执行完毕可以进行接下来的操作,就他通知相关的轮询函数,再由轮询函数执行接下来的操作,这就是I/O多路复用.
结尾
上面的内容只是很表面得介绍这几个概念,更适合入门理解
如果想学到更多关于这些概念的知识,可以参考一些权威书籍
另外很推荐这篇文章:
IO - 同步,异步,阻塞,非阻塞 (亡羊补牢篇)
以及知乎这个回答:
怎样理解阻塞非阻塞与同步异步的区别?