首先我们看看IO的五种模型:
同步和异步仅仅是关于所关注的消息如何通知的机制,而不是处理消息的机制.
也就是说:
同步的情况下,是由处理消息者自己去等待消息是否被触发
异步的情况下是由触发机制来通知处理消息者
-
阻塞,非阻塞:进程/线程要访问的数据是否就绪,进程/线程是否需要等待;
-
同步,异步:访问数据的方式,同步需要主动读写数据,在读写数据的过程中还是会阻塞;异步只需要I/O操作完成的通知,并不主动读写数据,由操作系统内核完成数据的读写。
一般来说,程序进行输入操作有两步:
1.等待有数据可以读
2.将数据从系统内核中拷贝到程序的数据区。
对于socket编程来说:
第一步: 一般来说是等待数据从网络上传到本地。当数据包到达的时候,数据将会从网络层拷贝到内核的缓存中;
第二步: 是从内核中把数据拷贝到程序的数据区中。
-----阻塞:
在linux中,默认情况下所有的socket都是阻塞的,一个典型的读操作流程大概是这样:
当用户进程调用了recvfrom这个系统调用,内核就开始了IO的第一个阶段:准备数据。对于network io来说,很多时候数据在一开始还没有到达(比如,还没有收到一个完整的UDP包),这个时候内核就要等待足够的数据到来。而在用户进程这边,整个进程会被阻塞。当内核一直等到数据准备好了,它就会将数据从内核中拷贝到用户内存,然后内核返回结果,用户进程才解除block的状态,重新运行起来。
所以,blocking IO的特点就是在IO执行的两个阶段都被block了。
-----非阻塞:常用于管道(非阻塞模式的使用并不普遍,因为非阻塞模式会浪费大量的CPU资源)