NIO[读]、[写]在同一线程(单线程)中执行,让CPU使用率最大化,提高处理效率
前几天写过一篇文章,讨论重写服务后,用ab进行压力测试,发现使用NIO后没提高什么性能,只是CPU使用率提高了,内存占用降低了。
之前的NIO实现模式,主要参考(基于事件的NIO多线程服务器)http://www.ibm.com/developerworks/cn/java/l-niosvr/
实现方式:把[读],[写]放在不同的线程中运行,主线程(Selector)中我使用了ConcurrentLinkedQueue队列,
//准备写
public static void readyWrite(SelectionKey key) { writeQueue.add(key); selector.wakeup(); //激活selector.select(); }
//准备读
public static void readyRead(SelectionKey key) { readQueue.add(key); selector.wakeup(); }
由于[读]、[写]是在各自的线程中运行,只要有读或写的时候,都要执行selector.wakeup();
我今天无意看到网上有人说,selector.wakeup();调用太多,影响性能。
我就试着把[读]、[写]重新放在一个线程中运行,然后再用ab压力测试,发现当开启持久连接后,性能上升了30%。
真没想到,会是这样的结果,不过由于服务中有的时候需要返回一些动态内容(有可能是一些耗时的业务),对于这部分情况肯定不能放在单线程中执行,不然,NIO会卡住,无法响应新用户的请求,我把这一部分动态页面放在一个线程池中执行:
//准备写
public static void readyWrite(SelectionKey key)
{
key.interestOps(SelectionKey.OP_WRITE);
}
//在多线程中(Page子类),准备写,需要同时激活selector.wakeup();
public static void readyWriteAndWakeup(SelectionKey key)
{
//测试发现,极少数情况下key 有可能=null,比如执行了Request.close()后
if (key != null)
{
key.interestOps(SelectionKey.OP_WRITE);
selector.wakeup();
}
}
//准备读
public static void readyRead(SelectionKey key)
{
key.interestOps(SelectionKey.OP_READ);
}
现在改为单线程后,CPU使用率提升不少,内存占用更低。
这对我来说,真是一个意外的收获
2012-06-11