BIO、NIO和AIO区别

计算机中常见的io模型主要分为BIO、NIO和AIO。
操作系统的io操作包括读写文件,socket操作等cpu分为内核态和用户态,出于安全考虑,所有的用户的应用程序都工作在用户态,系统调用工作在内核态,例如当应用程序需要进行读文件操作时候,由应用程序向操作系统发起系统调用,由操作系统从io设备将数据读到内核态然后将数据从内核态拷贝到用户态(例如缓冲区),应用程序拿数据完成文件的读取。这是个通用的过程,根据具体执行过程的不同可以分为BIO,NIO和AIO。
阻塞指的是进程状态为”wait”状态,CPU不会给进程分配时间片,只有当数据准备好时,进程从”wait”转为”running”时,CPU才会给进程分配时间片继续执行。而应用程序while(true)循环不是阻塞。
BIO
具体步骤如下:

  1. 应用程序发起系统调用,请求操作系统读数据;
  2. 操作系统切换到内核态,去读取IO设备的数据,将数据由IO设备读到内核;
  3. 读取完毕后将数据从内核复制到用户空间。
  4. 数据返回
    在这个读取数据过程中,系统调用一直没有返回数据,应用程序一直处于阻塞状态,等待数据准备就绪。
    假如说一个Socket通信程序的服务端,需要同时监听多个socket连接,a,b,c。其中a数据量大,耗费时间多,b很快,a在等待数据过程中,整个服务端处于阻塞状态,无法执行任何运算或响应任何的网络请求。效率比较低下。
    NIO
    BIO的问题在于应用程序一直处于等待数据准备就绪的状态,阻塞了整个应用程序。而BIO改进的地方就是,当数据没准备好的时候,内核直接告诉应用程序数据没有准备好就行了,不需要应用程序等待。当操作系统数据没有准备好时,立即返回,不需要阻塞等待,应用程序通过多次系统调用来等待数据操作完成。当有多个IO请求时候,每个都需要占用一个进程不断执行系统调用来查询数据是否准备完成,耗费大量的CPU资源。
    为了解决上面的问题,进化出了IO多路复用。
    假如说有3个IO操作,用一个线程专职负责轮询操作系统这三个IO操作的数据是否准备就绪,不需要每个IO操作都用一个线程去轮询。这就是多路复用。
    select专职监听各个IO操作是否就绪,此时应用程序也是阻塞的,当其中某个socket有数据准备就绪时,select返回通知应用程序,此时应用程序查找select监听的各个socket中哪个socket数据准备完成,执行后续操作。在这个过程中有个问题,应用程序还是需要挨个查询所有监听的socket查找数据准备就绪的socket,并且执行select调用时,还需要将全部监听的socket由用户空间复制到内核,执行效率不高,后续就产生了各种优化后的多路复用IO模型,如epoll。
    AIO
    NIO的过程是当操作系统数据准备好时通知应用程序,应用程序发起一起系统调用,将数据从内核复制到用户空间,然后应用程序读取数据做后续处理。异步调用采用了不同的方式,
    AIO和NIO最大的区别在于,AIO是当数据准备好并且将数据从内核复制到用户空间的时候才会通知应用程序,应用程序可以继续执行,不需要阻塞,当收到数据准备完成通知时候,应用程序也不需要再发起一次系统调用取数据,直接去用户空间取数据即可。

select
原理概述:
select 的核心功能是调用tcp文件系统的poll函数,不停的查询,如果没有想要的数据,主动执行一次调度(防止一直占用cpu),直到有一个连接有想要的消息为止。从这里可以看出select的执行方式基本就是不同的调用poll,直到有需要的消息为止。
缺点:
1、每次调用select,都需要把fd集合从用户态拷贝到内核态,这个开销在fd很多时会很大;
2、同时每次调用select都需要在内核遍历传递进来的所有fd,这个开销在fd很多时也很大;
3、select支持的文件描述符数量太小了,默认是1024。
优点:
1、select的可移植性更好,在某些Unix系统上不支持poll()。
2、select对于超时值提供了更好的精度:微秒,而poll是毫秒。
poll
原理概述:
poll本质上和select没有区别,它将用户传入的数组拷贝到内核空间,然后查询每个fd对应的设备状态,如果设备就绪则在设备等待队列中加入一项并继续遍历,如果遍历完所有fd后没有发现就绪设备,则挂起当前进程,直到设备就绪或者主动超时,被唤醒后它又要再次遍历fd。这个过程经历了多次无谓的遍历。poll还有一个特点是“水平触发”,如果报告了fd后,没有被处理,那么下次poll时会再次报告该fd。
缺点:
1、大量的fd的数组被整体复制于用户态和内核地址空间之间,而不管这样的复制是不是有意义;
2、与select一样,poll返回后,需要轮询pollfd来获取就绪的描述符。
优点:
1、poll() 不要求开发者计算最大文件描述符加一的大小。
2、poll() 在应付大数目的文件描述符的时候速度更快,相比于select。
3、它没有最大连接数的限制,原因是它是基于链表来存储的。
epoll
原理概述:
epoll同样只告知那些就绪的文件描述符,而且当我们调用epoll_wait()获得就绪文件描述符时, 返回的不是实际的描述符,而是一个代表就绪描述符数量的值,你只需要去epoll指定的一 个数组中依次取得相应数量的文件描述符即可,这里也使用了内存映射技术,这 样便彻底省掉了这些文件描述符在系统调用时复制的开销。
epoll的优点就是改进了前面所说缺点:
1、支持一个进程打开大数目的socket描述符:相比select,epoll则没有对FD的限制,它所支持的FD上限是最大可以打开文件的数目,这个数字一般远大于2048,举个例子,在1GB内存的机器上大约是10万左右,具体数目可以cat /proc/sys/fs/file-max察看,一般来说这个数目和系统内存关系很大。
2、IO效率不随FD数目增加而线性下降:epoll不存在这个问题,它只会对"活跃"的socket进行操作— 这是因为在内核实现中epoll是根据每个fd上面的callback函数实现的。那么,只有"活跃"的socket才会主动的去调用 callback函数,其他idle状态socket则不会,在这点上,epoll实现了一个"伪"AIO,因为这时候推动力在os内核。在一些 benchmark中,如果所有的socket基本上都是活跃的—比如一个高速LAN环境,epoll并不比select/poll有什么效率,相 反,如果过多使用epoll_ctl,效率相比还有稍微的下降。但是一旦使用idle connections模拟WAN环境,epoll的效率就远在select/poll之上了。
3、使用mmap加速内核与用户空间的消息传递:这点实际上涉及到epoll的具体实现了。无论是select,poll还是epoll都需要内核把FD消息通知给用户空间,如何避免不必要的内存拷贝就 很重要,在这点上,epoll是通过内核于用户空间mmap同一块内存实现的。
三者对比与区别:
1、select,poll实现需要自己不断轮询所有fd集合,直到设备就绪,期间可能要睡眠和唤醒多次交替。而epoll其实也需要调用epoll_wait不断轮询就绪链表,期间也可能多次睡眠和唤醒交替,但是它是设备就绪时,调用回调函数,把就绪fd放入就绪链表中,并唤醒在epoll_wait中进入睡眠的进程。虽然都要睡眠和交替,但是select和poll在“醒着”的时候要遍历整个fd集合,而epoll在“醒着”的时候只要判断一下就绪链表是否为空就行了,这节省了大量的CPU时间。这就是回调机制带来的性能提升。
2、select,poll每次调用都要把fd集合从用户态往内核态拷贝一次,并且要把current往设备等待队列中挂一次,而epoll只要一次拷贝,而且把current往等待队列上挂也只挂一次(在epoll_wait的开始,注意这里的等待队列并不是设备等待队列,只是一个epoll内部定义的等待队列)。这也能节省不少的开销

select,poll,epoll都是IO多路复用的机制。I/O多路复用就通过一种机制,可以监视多个描述符,一旦某个描述符就绪(一般是读就绪或者写就绪),能够通知程序进行相应的读写操作。但select,poll,epoll本质上都是同步I/O,因为他们都需要在读写事件就绪后自己负责进行读写,也就是说这个读写过程是阻塞的,而异步I/O则无需自己负责进行读写,异步I/O的实现会负责把数据从内核拷贝到用户空间。
epoll的优点:
1、没有最大并发连接的限制,能打开的FD的上限远大于1024(1G的内存上能监听约10万个端口);
2、效率提升,不是轮询的方式,不会随着FD数目的增加效率下降。只有活跃可用的FD才会调用callback函数;
即Epoll最大的优点就在于它只管你“活跃”的连接,而跟连接总数无关,因此在实际的网络环境中,Epoll的效率就会远远高于select和poll

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值