同步异步,阻塞非阻塞的区别
同步、异步
同步:用户进程发起IO后,进行就绪判断,轮询内核状态。
异步:用户进程发起IO后,可以做其他事情,等待内核通知。
阻塞、非阻塞
阻塞:用户进程访问数据时,如果未完成IO,调用的进程一直处于等待状态,直到IO操作完成。
非阻塞:用户进程访问数据时,会马上返回一个状态值,无论是否完成,此时进程可以操作其他事情。
IO模型
Linux下的五种I/O模型
阻塞I/O(blocking I/O)
非阻塞I/O(nonblocking I/O)
I/O复用(select和poll) (I/O multiplexing)
信号驱动I/O(signal driven I/O (SIGIO))
异步I/O (asynchronous I/O (the POSIX aio_functions))
Tip:前四种都是同步,只有最后一种才是异步I/O。
I/O发生时涉及的对象和阶段
Linux为了OS的安全性等的考虑,进程是无法直接操作I/O设备的,其必须通过系统调用请求内核来协助完成I/O动作,而内核会为每个I/O设备维护一个buffer。
对于一个network I/O (这里我们以read举例),它会涉及到两个系统对象,一个是调用这个I/O的process (or thread),另一个就是系统内核(kernel)。当一个read操作发生时,它会经历两个阶段:
- 用户进程发起请求,内核接收到请求,从I/O设备中获取数据到buffer,等待数据准备 (Waiting for the data to be ready)
- 将buffer中的数据copy到用户进程的地址空间,即将数据从内核拷贝到进程中 (Copying the data from the kernel to the process)
记住这两点很重要,因为这些I/O Model的区别就是在两个阶段上各有不同的情况。
阻塞IO
从上图可以看到在整个过程中,当用户进程进行系统调用时,内核就开始了I/O的第一个阶段,准备数据到缓冲区中,当数据都准备完成后,则将数据从内核缓冲区中拷贝到用户进程的内存中,这时用户进程才解除block的状态重新运行。
所以,Blocking I/O的特点就是在I/O执行的两个阶段都被block了。
非阻塞IO
从上图可以看到在I/O执行的两个阶段中,用户进程只有在第二个阶段被阻塞了,而第一个阶段没有阻塞,但是在第一个阶段中,用户进程需要盲等,不停的去轮询内核,看数据是否准备好了,因此该模型是比较消耗CPU的。
IO复用
从上图可以看到在I/O复用模型中,I/O执行的两个阶段用户进程都是阻塞的,但是两个阶段是独立的,在一次完整的I/O操作中,该用户进程是发起了两次系统调用。
信号驱动IO
该模型也叫作基于事件驱动的I/O模型,可以看到该模型中,只有在I/O执行的第二阶段阻塞了用户进程,而在第一阶段是没有阻塞的。
乍看起来感觉和非阻塞模型很相似,其实不同之处就在于,该模型在I/O执行的第一阶段,当数据准备完成之后,会主动的通知用户进程数据已经准备完成,即对用户进程做一个回调。该通知分为两种,一为水平触发,即如果用户进程不响应则会一直发送通知,二为边缘触发,即只通知一次。
异步IO
在该模型中,当用户进程发起系统调用后,立刻就可以开始去做其它的事情,然后直到I/O执行的两个阶段都完成之后,内核会给用户进程发送通知,告诉用户进程操作已经完成了。