Stevens在文章中一共比较了五种IO Model:
blocking IO
nonblocking IO
IO multiplexing
signal driven IO
asynchronous IO
由于signal driven IO在实际中并不常用,所以我这只提及剩下的四种IO Model。
对于一个network IO (这里我们以read举例),它会涉及到两个系统对象,
一个是调用这个IO的process (or thread),另一个就是系统内核(kernel)。
当一个read操作发生时,它会经历两个阶段:
1 等待数据准备 (Waiting for the data to be ready)
2 将数据从内核拷贝到进程中 (Copying the data from the kernel to the process)
阻塞式I/O模型:第一步一次system call
第一步通常涉及等待数据从网络中到达。当所有等待分组到达时,它被复制到内核中的某个缓冲区。
第二步就是把数据从内核缓冲区复制到应用程序缓冲区。
非阻塞式I/O:第一步多次system call,第二步一次
当用户进程发出read操作时,如果kernel中的数据还没有准备好,
那么它并不会block用户进程,而是立刻返回一个error。
从用户进程角度讲 ,它发起一个read操作后,并不需要等待,而是马上就得到了一个结果。
用户进程判断结果是一个error时,它就知道数据还没有准备好,于是它可以再次发送read操作。
一旦kernel中的数据准备好了,并且又再次收到了用户进程的system call,
那么它马上就将数据拷贝到了用户内存,然后返回。
所以,用户进程其实是需要不断的主动询问kernel数据好了没有。
I/O多路复用:第一,二步开始各一次system call
虽然I/O多路复用的函数也是阻塞的,但是其与以上两种还是有不同的,
I/O多路复用是阻塞在select,epoll这样的系统调用之上,而没有阻塞在真正的I/O系统调用如recvfrom之上.
信号驱动式I/O:和多路复用差不多,只是用信号代替通知,不常用。
异步I/O:第一步一次system call
工作机制是告知内核启动某个操作,并让内核在整个操作(包括将数据从内核拷贝到用户空间)完成后通知我们
生活实例:老张要烧水,再泡茶喝
1.老张放水壶到火上,等水开了,再泡茶喝。
2.老张放水壶到火上,反复去看会儿电视,反复回来check水开了没,反复几次水开了开始泡茶喝。
3.老张在走廊烧水,其他居民也在楼道烧水,有个在走廊乘凉的邻居,让ta帮忙看谁家的水开了就帮忙喊下,然后开始泡茶。
4.老张买了个自动冲茶机,打开后老张就去看电视了。听到滴滴滴的提示声知道茶已经泡好了。
前3个其实都是同步的。3的阻塞就是哪个看护者调用。
http://blog.csdn.net/historyasamirror/article/details/5778378
https://www.zhihu.com/question/19732473