使用传统jdk api编写的OIO应用于NIO应用进行比较。
非netty OIO
程序主要包括两部分,server/client
server:在本地监听8000端口,死循环接收client传输的信息,如果接收到请求,新启一个线程并对连接输出“Hi!\r\n”。
client:使用线程池,启动2000个线程,对server进行socket请求,检测结果是否返回“Hi!”
程序如下
server
|
|
client
|
|
执行server,后执行client,观察console中的日志
受制于本地机器
server只接收到了471个请求
471 Accepted connection from Socket[addr=/127.0.0.1,port=10993,localport=8000]
client接收到了471个“Hi!”。并且出现了大量的异常
所以,在并发较高的情况下,使用OIO并不是一个明智的选择。
非netty NIO
在刚刚的OIO中使用同步不能胜任较高并发下的通讯处理
将OIO修改为NIO,检测是否能胜任。
将OIO的server代码修改如下
|
|
client保持不变,使用2000个线程进行压力测试
结果server端只收到了173个请求,大部分的请求出现了如下错误
在new Socket申请本地资源时出现了异常。
|
|
虽然从返回数据的条目来看nio并不占优势,但是从资源利用率来看,是好上不少的,执行OIO程序,eclipse出现了假死现象,执行NIO时并没有,并且机器内存使用率也可以直观的看出两者占用资源的情况,具体的可以通过jvisualvm检测线程的CPU和内存占用情况进行分析。由于只有一台机器,如果有条件,应该使用两天机器进行测试,只需要比较server的性能即可。
netty IO
netty OIO
在使用普通jdk api后,我们使用netty来完成服务端的编写
server
我们使用上述的压测代码进行测试
|
|
服务端共接收到了403个socket请求,同时机器并没有出现卡顿严重等现象。说明netty对socket接收的情况比普通的要更好,虽然使用的是阻塞的方式进行处理,但是并未占用太多的系统资源。
netty NIO
因为Netty为每种传输的实现都暴露了相同的API,所以无论选用哪一种传输的实现,你的代码几乎不受影响。在所有的情况下,传输都依赖于 interface Channel、ChannelPipeline和ChannelHandler。
故代码修改如下,与OIO版本相比,只有选择的channel不同
|
|
执行结果
|
|
使用netty非阻塞方式,客户端2000个线程全部执行完成,并且电脑资源并未出现占用过渡现象,是本次试验中唯一一个执行完全的例子。可见,netty在处理server端请求时的强大处理能力。
所以构建网络应用时,使用netty的NIO是一个最佳实践