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

java NIO引用自http://blog.csdn.net/shidcai/archive/2006/03/19/629261.aspx

2006-03-20 18:22 597 查看
为了实现高性能的MOM(消息中间件),学习了java的NIO,想利用NIO技术来改善网络通讯的性能。学习NIO的时候,看了书上的,也找了网上相当 多的资源,但大部分的资料都是比较粗浅的,入门级,深入的基本没有。不过,对于了解和学习NIO来说已经足够了。真正的领会还是需要在实践中获得的。
NIO的技术在JDK1.4中出现。NIO最大的特点有两个:一个是块状读写;另外一个是多路复用技术(multiplex)。第一个特点改变了老式IO 中,每次读写只有一个字节(stream)和两个字节(reader)的方式,提高了读写的速度;第二个特点改变了原来读写socket时候阻塞的同步状 况,使socket的读写具有的异步的功能。第二个特点比较重要,NIO的异步读写据说大大提高了网络通讯的能力,尽管没有C++的快,但至少不再象以前 那样,一说起java首先想到的是“性能低下”。这一点,在网上可以搜到一大把的资料。

在JTangMQ消息中间件中,使用了NIO实现了通讯层。为了方便起见,客户端和服务器都采用了同一块代码,也就是说,客户端和服务器端都是非阻塞的, 编解码和读写socket的方式都一样。然而,在测试过程中发现,客户端在向服务器发送消息的时候,cpu的占用率在80%左右,带宽只占了5% (100M的带宽);服务器端的配置比较高,cpu的占用率在10%左右,带宽占有率一样。通过java的profiler工具分析,发现客户端的cpu 时间主要是消耗在选择器的select操作之上(NIO的多路复用),而select操作主要调用的是poll函数,这个函数是sun公司提供的关于选择 器的缺省类。根据网上的资料,这个操作是一个轮询socket的同步操作,它的主要功能就是不断地去查询向该选择器注册的socket,看看有没有可做的 操作,如有,则返回,没有,继续不断地轮询。也就说,分配的cpu的时间基本上被消耗在poll上了。

现在问题就出来了。既然poll占用这么多时间,是因为没有什么东西可以写入socket或者从socket中读取;那么,就应该给“提供读写数据的线 程”更多的cpu时间,使得每一次的poll都有可作的操作,使时间耗费在读写socket之上,而不是poll之上。然而,从分析数据中看来,poll 线程显然比“提供读写数据的线程(wr线程)”占用了更多的cpu时间,假设他们的优先级相同,也假设操作系统是公平的分配cpu时间,那么它们得到的 cpu时间应该是一样的,此时,造成它们占用cpu时间不同的原因就很可能是这样:在相同的时间内,wr线程提供的数据量根本不够poll线程处理, poll线程处理在相同的时间内处理这些数据绰绰有余,那么,poll线程更多的时间就耗费在轮询上了。到这里,我们假设的是这两个线程分配到了相同的时 间,所以,即使poll线程大部分时间是在做poll轮询操作,那么所占用的时间最大值也是有限的,不会超过线程分配得到的时间。但是,如果此时尽管wr 线程得到了cpu时间,但是它在处理过程中主动放弃cpu(比如执行wait操作),那么,在cpu时间总量相等的情况下,由于poll线程没有执行 wait操作,因此,就会得到更多的cpu时间,这样,就会出现上面的分析的情况,大部分的cpu时间都给poll的轮询操作了。

由此分析,如果使wr线程不断的运行,而使poll线程在没有数据的时候放弃cpu时间,就应该可以减少poll线程的轮询操作,而使wr线程得到更多 的cpu时间,提供更多的可供读写的数据,提高读写的效率。然而,由于poll轮询操作是一个不间断的过程,是sun公司提供的底层的api,是无法修改 的。所以,就要放弃poll操作,也就是要放弃选择器。换句话说,就是客户端最好是不要采用非阻塞的方式。

综上所分析,如果客户端采用非阻塞的方式, 应该是可以提高客户端读写socket的速度的。而服务器端由于要同时连接大量的客户端,还是继续采用非阻塞方式为好。

这只是分析的结果,还没有具体实验过。不知道有没有人遇到过类似的问题,请不吝赐教。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: 
相关文章推荐