看了知乎大佬的文章,写点总结。
一、linux的IO操作分为两个阶段:
- 数据准备阶段: 内核接收来自外部的数据
- 数据拷贝阶段: 内核缓冲区 —> 用户缓冲区
二、几种IO模型:
- 阻塞模型
recvfrom一直等着IO操作的两个阶段。
- 非阻塞模型
recvfrom不会一直等,但会过一段事件就查看以下IO第一阶段是否完成,如果完成继续执行第二阶段。
- IO多路复用:select、poll、epoll
这三个函数本身是阻塞的,即调用之后会卡在这三个函数这,直到函数处理完毕。但是没有阻塞在真正的I/O系统调用如recvfrom之上,因为得到通知的时候,一定是有的socket已经完成了第一阶段,还需要recvfrom调用完成第二阶段。
- 信号驱动式IO
不太用,没研究。
- 异步IO
真正的异步操作,只要调用了aio,内核把IO过程的两部分全给你办完了之后才通知你,这时候你只需要从你数组里拿出来就行了。
三、同步和异步的分析理解
1、POSIX对同步和异步的定义:
- 同步I/O操作:导致请求进程阻塞,直到I/O操作完成;
- 异步I/O操作:不导致请求进程阻塞。(不导致阻塞是指在IO过程的两个子过程都不会导致)
2、分析同步和异步
IO模型的1、2、3、4都属于同步模型,因为这些IO模型在IO过程第一阶段不一样;但是第二阶段一样,都需要在recvfrom调用下,阻塞的等待数据从内核缓冲区复制到用户缓冲区。是存在阻塞被调用进程的情况的。
真正的异步IO模型是第五种类型,因为进程在IO过程的两部分都没有被阻塞。不存在阻塞被调用进程的情况。
四、总结
-
阻塞,非阻塞:进程/线程要访问的数据是否就绪(指IO的第一阶段),进程/线程是否需要等待;
-
同步,异步:访问数据的方式,同步需要主动读写数据,在读写数据的过程中还是会阻塞;异步只需要I/O操作完成的通知,并不主动读写数据,由操作系统内核包办全过程,用户进程只需要在内核通知的时候去处理数组中的数据就行了。