浏览 3968 次
锁定老帖子 主题:关于NIO的服务端实现性能
精华帖 (0) :: 良好帖 (0) :: 新手帖 (0) :: 隐藏帖 (0)
|
|
---|---|
作者 | 正文 |
发表时间:2012-09-18
本来使用RMI的方式分开本地的方法供远程调用,现在自己写了一个NIO的服务端实现,有几个问题不清楚.
我使的方式是有CPU个数的Selector实例,每个实例有一个线程专门去跑. 其中一个Selector只注册了ON_ACCEPT事件,响应这个事件的方法中有这样一段
synchronized (ioSelectorsSyns.get(selector)) { selector.wakeup(); socketChannel.register( selector, SelectionKey.OP_READ, new BufferManager()); }
其他几个线程内一个循环
int selectNum = 0; while (true) { if (close) { break; } synchronized (ioSelectorsSyns.get(selector)) { } selectNum = selector.select(ioSelectorWaitTime); if (selectNum == 0) { continue; } Set<SelectionKey> readyKeys = selector.selectedKeys(); Iterator<SelectionKey> keyIter = readyKeys.iterator(); while (keyIter.hasNext()) { try { key = keyIter.next(); keyIter.remove(); if (key.isValid()) { if (key.isReadable()) { //可以读取数据 readable(key, this.readBuffer); } if (key.isWritable()) { //可以写数据 writeable(key); } } } catch (IOException ex) { abandonConnection(key); } catch (Exception ex) { getLog().errorLog(ex); } } } 这里使用了Selector.select()方法 ,这个方法阻塞到有事件就取消阻塞.但是我查API上并不是这么说的.
<!--StartFragment--> 阻塞在 select() 或 select(long) 方法之一中的某个线程可能被其他线程以下列三种方式之一中断: 完整的代码在附件我上传了,那位可以帮我看看性能问题.
这里主要是注册事件时的同步,我不知道是不是这里产生了问题.因为刚开始时我只注册了读事件,等业务逻辑执行完后有结果才注册了写事件.
这里几个线程中我换成使用Selecto.selectNow()方法虽然CPU占用很高,但是响应速度就快.
声明:ITeye文章版权属于作者,受法律保护。没有作者书面许可不得转载。
推荐链接
|
|
返回顶楼 | |
发表时间:2012-09-19
select(time)方法有可用通道时便会返回,并不一定要等到指定的time到达
|
|
返回顶楼 | |
发表时间:2012-09-19
mina.
|
|
返回顶楼 | |
发表时间:2012-09-19
本来我也认为是这样,但是API上却没有这样写. 我自己运行下来好像我不运行wakeup的话select()方法一直阻塞.
使用selectNow()虽然CPU占用满了,但是注册事件时不需要调用wakeup方法和进行同步了所以好像测试下来响应更快了.... |
|
返回顶楼 | |
发表时间:2012-09-20
呵呵 兄弟,
第一点 select方法肯定是有事件就会取消阻塞,api也是这样讲的。 It returns only after at least one channel is selected, * this selector's {@link #wakeup wakeup} method is invoked 第二点 我觉得有可能是 select和register有锁冲突详见我的blog http://xiaoz5919.iteye.com/blog/1518473 你可以先register然后再wakeup 先wakeup再register你有什么考虑吗 |
|
返回顶楼 | |
发表时间:2012-09-20
先wakeup的原因是,当select()方法阻塞的时候,register()也会被阻塞.
所以我同步了注册事件和select()循环 synchronized (ioSelectorsSyns.get(selector)) { selector.wakeup(); socketChannel.register( selector, SelectionKey.OP_READ, new BufferManager()); } 循环里有一个空的同步块来防止select()方法再次阻塞. |
|
返回顶楼 | |
发表时间:2012-09-20
etnet 写道 先wakeup的原因是,当select()方法阻塞的时候,register()也会被阻塞.
所以我同步了注册事件和select()循环 synchronized (ioSelectorsSyns.get(selector)) { selector.wakeup(); socketChannel.register( selector, SelectionKey.OP_READ, new BufferManager()); } 循环里有一个空的同步块来防止select()方法再次阻塞. 仁兄说得对 不能先register再wakeup,这样会有锁冲突。我上午没仔细看,汗! |
|
返回顶楼 | |
发表时间:2012-09-20
看过Tomcat的nio connector 或者 mina netty之类 他们为了避免这种冲突,一般不是直接执行register,而是在添加一个注册事件添加到事件队列里。然后再执行wakeup
比如这样 handlerRegister(); keyCount = selector.select(selectTimeout); 每次在执行select之前执行register避免冲突 |
|
返回顶楼 | |
发表时间:2012-09-21
多谢提醒,还真是没想到去看一下这些东西.
|
|
返回顶楼 | |