通信中的BIO与NIO

从BIO到NIO

BIO阻塞式的IO,NIO非阻塞式的IO。这里从一个通信的并发问题讲起。

我们知道当并发量大的时候我们能够采用的解决或者是扩展方式有两种:横向扩展(增大线程的数目),纵向扩展(使得每个线程得到良好的使用)。

 

在并发量大的时候我们可以启用多个线程,比如说我们常用的手段就是线程池。但是如果线程阻塞每个线程还是得不到充分的利用。这时候我们就应该使用NIO来使得每个线程的利用更加的充分,这个操作属于纵向扩展

 

这里就具体的列出BIO通信的缺点

①基于BIO的通信,每来一个客户端就会启动一个线程这样的话就会产生大量的线程。

同时由于大量的线程,会使得CPU来回切换的成本增高。

②由于阻塞,比如说read,write,accept,connect这些方法都会阻塞。所以单个线程的利用效率低。

③当一个线程被占用但是它本身并没有工作,这样的话这个线程就会出现置空期,这时CPU就只是无意义的空转。

 

NIO与BIO各有优缺点,NIO可能不擅长处理长请求(因为它可能受到一些资源调度器的控制被来回切换)。所以一般在处理长请求比如说下载大的文件使用BIO更加合适。

多路选择的引出

多路选择就器就像是一个资源调度器一样,在他的上面注册了很多的通信的线程。它的作用就是在一些线程空闲的时候将这个线程空出来供其他客户端使用。而当监听到一个客户发起请求或者是传输动作的时候就会个当前的操作分配线程。这样的话就能够灵活的使用有限的线程打出最大的伤害。

 

FileChannel与ZeroCopy

我们平常看起来的远端文件传输的背后起始隐藏着大量的拷贝操作如下图所示:

通信中的BIO与NIO

①首先从硬盘上拷贝到ReadBuffer中,这里的ReadBuffer是内核态(一种权限较高的状态,可以享有各种底层权限)。

②然后拷贝到ApplicationBuffer(这里是用户态,用户态就是将内核态的功能删减了很多然供用户来调用)。

③将ApplicationBuffer操作之后(事实上这里并不去操作),然后拷贝到SocketBuffer中。

④最后将SocketBuffer中的内容拷贝到NIC(网卡)的缓存中。

ZeroCopy的基本原理就是将中间的两步复制操作删除。如下图所示:

通信中的BIO与NIO

这样的话也就提升了效率。Java中Channel类就是基于ZeroCopy的。

transferFrom(ReadableByteChannel src, long position, long count)