socket通信时,总是看到两对词汇不停的出现,但究竟他们各自分别代表什么内容,我就不甚了解了,甚至有的时候会把他们混淆起来叫,在查过UNP之后,有了一个比较粗浅的认识,在这里说一说.
通信,或者IO过程,总是分成了两个部分,第一个部分是检查数据是否准备就绪,第二个部分才是真正的IO操作,用户--OS缓冲区之间的数据移动,OS缓冲区--网络/磁盘等的一系列操作.
read操作可以这样理解:
1.读文件时,应该先检查文件数据是否就绪,比如被其他进程锁住,或者超出了文件的范围,那么此时文件的数据是没有就绪,无法读取的;如果没有上述情况,那么我们就开始真正的内容的复制
2.读管道时,首先是判断管道内有没有可读内容,如果没有的话,此时管道的数据就是没有就绪的,无法读取;如果没有上述情况,我们就可以进行真正IO操作获取管道内容
3.读网络通信时,首先是判断连接是否有效,该信息是否到达本机,如果信息不全,或者压根就没有,那么此时的网络数据就是没有就绪的,无法读取;否则,我们就可以通过IO操作获取内容
写时类似
也就是说,针对每个IO过程,我们都要看到两个阶段,一是数据的检验,二是数据的操作,而标题上两对词汇的不同之处,就在于这两个阶段的不同
阻塞和非阻塞是主要针对的是第一阶段,即数据的检验,二者在数据就绪的情况下没有区别,但是当数据没有就绪时,阻塞调用一般会等待数据就绪,从而"堵"住了进程,但非阻塞调用则会马上返回,通过返回值或者errno来反应目前的数据情况,常见的前者比如一般的read操作,后者则如设置了NONBLOCK的read操作.二者仅仅是第一阶段的不同,不管是哪个read,等到数据就绪真正读的时候,进程同样不能做其他任何事情,这就引出了我们的同步/异步
同步和异步主要针对第二阶段,也就是真正数据操作,如上所述,read和nonblock的read在数据就绪时,都会"堵"住进程,直到完成IO操作,在数据操作时,也就是真正的IO时"堵"住进程的,就叫做同步,否则,就叫做异步,比如aio调用,aio_read之后直接返回,数据操作完全有OS完成,之后通过信号/回调函数来通知进程操作完成.同步/异步不在于第一阶段表现如何,而是当进行真正IO操作时的表现,堵了就是同步,不堵就是异步.
由此回头来看Linux提供的一些高级的调用,select/poll/epoll基本都是针对第一阶段的调度,其价值不在于快速,而在于大规模的处理,就本质而言,调度成功后我们仍然通过同步操作来完成相关通信,不同之处在于,可能此时IO的两个阶段分的比较开,数据检验在调度中,有OS内部实现,数据操作(就绪的数据)被我们人为的推后了.而这种人为的推后,很多时候和异步很像,但仍然不是异步.
需要注意的是,此时同步/异步都是形容IO操作的,在现实中人们通常将分割开来的一系列操作成为异步,比如事件驱动的调度模型,就被很多人成为异步,此时的异步不是形容IO操作的异步,而是指请求和处理的分割,请求不是原地处理,而是进入请求队列,一般通过回调函数在合适的时候处理,从而形成异步效果.不要搞混这两个不同的概念.