论坛首页 Java企业应用论坛

关于NIO的服务端实现性能

浏览 3921 次
精华帖 (0) :: 良好帖 (0) :: 新手帖 (0) :: 隐藏帖 (0)
作者 正文
   发表时间:2012-09-18  
nio

本来使用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) 方法之一中的某个线程可能被其他线程以下列三种方式之一中断:

  • 通过调用选择器的 wakeup 方法,
  • 通过调用选择器的 close 方法,或者
  • 在通过调用已阻塞线程的 interrupt 方法的情况下,将设置其中断状态并且将调用该选择器的 wakeup 方法。

完整的代码在附件我上传了,那位可以帮我看看性能问题.
这里主要是注册事件时的同步,我不知道是不是这里产生了问题.因为刚开始时我只注册了读事件,等业务逻辑执行完后有结果才注册了写事件.
这里几个线程中我换成使用Selecto.selectNow()方法虽然CPU占用很高,但是响应速度就快.
  • NIO.zip (7.4 KB)
  • 下载次数: 30
   发表时间:2012-09-19  
select(time)方法有可用通道时便会返回,并不一定要等到指定的time到达
0 请登录后投票
   发表时间:2012-09-19  
mina.
0 请登录后投票
   发表时间:2012-09-19  

本来我也认为是这样,但是API上却没有这样写.

我自己运行下来好像我不运行wakeup的话select()方法一直阻塞.

 

使用selectNow()虽然CPU占用满了,但是注册事件时不需要调用wakeup方法和进行同步了所以好像测试下来响应更快了....

0 请登录后投票
   发表时间: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你有什么考虑吗

0 请登录后投票
   发表时间:2012-09-20  
先wakeup的原因是,当select()方法阻塞的时候,register()也会被阻塞.

所以我同步了注册事件和select()循环

synchronized (ioSelectorsSyns.get(selector)) {
            selector.wakeup();
            socketChannel.register(
                    selector, SelectionKey.OP_READ, new BufferManager());
}

循环里有一个空的同步块来防止select()方法再次阻塞.
0 请登录后投票
   发表时间: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,这样会有锁冲突。我上午没仔细看,汗!
0 请登录后投票
   发表时间:2012-09-20  
看过Tomcat的nio connector 或者 mina netty之类 他们为了避免这种冲突,一般不是直接执行register,而是在添加一个注册事件添加到事件队列里。然后再执行wakeup
比如这样
  handlerRegister();
  keyCount = selector.select(selectTimeout);

每次在执行select之前执行register避免冲突
0 请登录后投票
   发表时间:2012-09-21  
多谢提醒,还真是没想到去看一下这些东西.
0 请登录后投票
论坛首页 Java企业应用版

跳转论坛:
Global site tag (gtag.js) - Google Analytics