您的位置:首页 > 理论基础 > 计算机网络

计算机网络IO:阻塞、非阻塞、同步、异步以及select与epoll

2014-05-21 17:30 716 查看
本文旨在原理性的揭示网络IO模型以及select和epoll的区别,在次并不探讨实现细节,另外,讨论阻塞与非阻塞、同步与异步往往是上下文相关的,文本的上下文如题就是linux IO,下文中IO操作就以read来举例。

首先明确一点,一次IO操作分两个阶段:1 等待数据准备就绪 2 将数据从内核拷贝到用户进程空间

阻塞IO:首先用户进程发起read系统调用,kernel开始准备数据,一般的,对于网络IO来说,大部分情况下当用户进程发起read调用的时候数据尚未到达,这个时候kernel一直等待数据到达,在用户进程这一侧,整个进程会被阻塞。当数据到达后,kernel就把准备妥当的数据从内核空间拷贝到用户进程空间,然后kernel返回,用户进程被唤醒,因此,阻塞IO在一次IO操作的两个阶段均被阻塞了。

非阻塞IO:当用户进程发起read系统调用时,如果内核还没收到数据,则此次系统调用立即返回一个错误而不是阻塞整个进程,用户进程需要通过此次调用的返回值判断是否读到了数据,如果没有则隔一段时间再次发起read系统调用,如此不断轮询,在用户进程轮询期间,kernel一直在等待数据到达,当数据准备妥当后,用户进程发起的read系统调用时,kernel负责将数据拷贝到用户进程空间,直到拷贝完成,read操作返回,也就是在这一阶段(第二阶段)非阻塞IO表现出的其实一个同步操作,因为从内核拷贝数据到用户进程空间的这段时间内read是一直等待直到完成的,因此,非阻塞的IO是属于同步IO的,也就是说非阻塞IO操作在第一阶段是不阻塞的,在第二阶段是阻塞的。

同步IO:一个同步IO操作会导致进程阻塞直到IO操作完成,所以,阻塞IO、非阻塞IO、以及本文未提及的IO多路复用都属于同步IO。

异步IO:一个异步IO操作不会引起进程的阻塞。

这里面大家可能分不清非阻塞和异步IO,甚至会认为非阻塞就是异步了,其实不是的,回到本文开头部分,我们说一次IO操作分两个阶段,第一阶段是等待数据,第二阶段是拷贝数据(内核到用户空间),非阻塞IO操作在数据还没有到达时是立即返回的,这一点表现的跟异步一样,但是在第二个阶段,当数据准备妥当的时候,非阻塞IO是阻塞的,直到数据拷贝完成,这一点表现的与异步IO完全不一样,异步根本不关心你的数据是否到达以及你的数据是否拷贝完成,异步发起一次IO操作后就去干别的事儿了,直到内核发出一个信号通知这一事件,它才会转回来继续处理。

select与epoll

select与epoll都是IO多路复用模型,它们都是监视一组socket看是否有数据准备就绪,select和epoll会一直阻塞直到她们监视的一个或多个套接字描述符上数据准备就绪,当在某个或某几个套接字描述符上有数据到达时,对于select而言,它需要遍历这组描述符以便确定到底是哪一个描述符上数据到达了,所以时间复杂度是O(n),而对于epoll而言,它不是通过遍历(或者叫轮询)这组描述符来确定是哪个描述符数据准备妥当,而是通过事件的方式,以事件的方式通知epoll是哪个描述符到达数据了,因此时间复杂度是O(1)。

可能说的很罗嗦,只是想尽量的把原理弄清楚,原理清楚了再看实现细节才能做到游刃有余。

参考文章:特别建议大家看看这两篇文章,我相当于是看完这两篇文章在这里做的总结。

http://blog.csdn.net/historyasamirror/article/details/5778378

http://yaocoder.blog.51cto.com/2668309/888374
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: