问题7:NIO、多路复用

BIO,NIO,多路复用,AIO

概念理解

同步和异步 关注点在于处理机制,同步在于等待上一条语句调用后的返回结果才继续,异步在于事件响应回调机制,语句调用后直接返回,等触发事件之后,自动调用写好的回调函数

 

阻塞非阻塞 关注点在于线程是否挂起 阻塞在于得到结果之前会挂起线程,非阻塞在于不会挂起自己

 

IO流程

·一是数据读取:把数据从磁盘读到内核空间,我们都知道,read属于系统调用,用户级线程是无法操作的,只能交给内核线程去处理,而内核线程首先要找到数据,并读到内核空间中。

·二是数据复制:把数据从内核空间读取到用户空间。然后用户线程才可以使用这些数据

三大IO模型的解释

BIO

 

用上面的概念理解一下,write和read方法调用不会直接返回,而且还会把当前线程挂起来。这个有趣了,当前线程挂起还怎么操作呢?写和读其实都需要内核线程操作,内核线程在读和写的时候用户线程被挂起了。

BIO 在这两个步骤都是做不了其他事情的,在用户程序中看起来就是卡死。第一个步骤中用户线程阻塞挂起,第二个步骤中用户线程去从内核空间拷贝来用户空间。

 

NIO

NIO把第一个步骤分成多个小阻塞,本来第一个步骤是一个大阻塞,现在分为多个小阻塞(”检查“),这样当前线程就会一直轮询,类似于CAS,不挂起线程但是cpu一直跑,没有数据的准备阶段十分浪费资源

但是第二部分还是需要用户线程去copy

多路复用

多路复用采用的操作系统底层的模型,select poll epoll模型,想比于上面的NIO模式,这个能处理多个IO请求上述NIO在第一阶段一直轮询是否数据准备好,浪费大量cpu,如果多个NIO,那么就多个线程一起轮询。所以引发出IO复用模式,调用底层的select poll epoll等函数,让操作系统去轮询,查询到一个或者多个就返回。如果一个都没有还是会阻塞,本质上就是把轮询交给了内核。现在大部分Linux系统采用epoll模式,例如:Java NIO网络编程中,调用select方法,其本质上调用epoll_wait返回准备好的IO。这个的好处在于一个单独线程就能调度很多IO请求业务。轮询交给了内核。

 

第二部分还是得用户线程去copy回数据到用户空间。但是采用直接内存空间,做内存映射就能做到零拷贝节约这一次的时间

 

AIO

AIO这边就程序一调用read就离开返回,然后写好回调函数,或者返回future,两种模式回调式和将来式,IO两个步骤都是内核去完成和用户线程没关系,内核完成之后通知下用户线程。这意味着AIO两个步骤都能做自己的事情。

 

总结

同步就是上述两个过程都阻塞了

非阻塞就是上述第一个过程你没有阻塞,但是用户线程必须不断的询问os,类似于CAS,cpu疯狂占用,数据是否从磁盘拷贝到内和空间了,如果拷贝好了,则在数据复制的过程阻塞。所以所有的同步过程,在第二阶段都是阻塞的,尽管这是非阻塞的调用。

多路复用:和非阻塞一样,在第二阶段也是阻塞的,但是第一阶段不再由自己去询问操作系统,而是统一交给一个内核线程去处理,现在才有epoll模型,这个比较快,但是没有事件准备好的情况下还是会阻塞,当你的数据读取完成,这个线程就发送一个信号给原先发起系统调用的用户线程,并开始数据拷贝了。

异步:上述两个过程都是非阻塞的。