论坛首页 Java企业应用论坛

非阻塞socket的selector.wakeup()功能讨论

浏览 14321 次
精华帖 (0) :: 良好帖 (3) :: 新手帖 (0) :: 隐藏帖 (0)
作者 正文
   发表时间:2010-04-22  
我看了一篇关于 java socket selector 深度分析的文章.
地址:http://blog.csdn.net/haoel/archive/2008/05/04/2379586.aspx
作者:chenhao

里面的观点我不关心,但是刚好我看到selector.wakeup()这个功能我们自己的程序里也在使用.
我们程序的逻辑基本是这样(server):

处理完请求之后需要发回执.这个时候就把 session 对象(session里包含单独用户的socketchannel)丢回 socketlistener 的队列.然后触发socketlistener里面的selector.wakeup()方法.
也就是:每当有回执包需要发送给客户端的时候就把selector.wakeup()执行一次.

除此之外,还有退出侦听的时候也执行了selector.wakeup:
	public final synchronized void exit() {
		this.readORwrite = false;
		this.selector.wakeup();
	}

===============================================================
我仔细看了那个文章的回帖.其中一贴:
引用
不是一直保持一个loopback connection,而是需要的时候才发起一个loopback connection。我能想到的需要的时候就只有一个,就是程序结束了,要让select“优雅”的关闭。为了一个只在整个程序生命周期使用不到万分之1的功能花费一个链接资源的话不是很值得


那么,这是否证明我们这个程序书写有问题呢?
我们这个程序在每次有回执包产生的时候都要调用一次selector.wakeup();  这样是否影响我们程序的效率?

还有,selector.wakeup();这个东西到底有什么用呢?我还是比较模糊.
   发表时间:2010-04-22   最后修改:2010-04-22
selector.wakeup主要是为了唤醒阻塞在selector.select上的线程,让该线程及时去处理其他事情,例如注册channel,改变interestOps、判断超时等等。
selector的实现其实跟大多数跨平台的网络框架的实现没有两样,如果你了解过ACE框架的话,也会发现它也是在windows上使用loopback connection来实现notify的机制。

从你的描述来看,你们的用法没错,及时唤醒selector去处理写,这个没有问题。频繁的wakeup是对性能有影响,因此这里可以做个优化,在将session对象加入队列之前,你可以判断队列是否为空,为空的时候才在加入队列后去唤醒select阻塞的线程处理队列里的数据,避免在队列有数据的时候重复唤醒。也就是类似这样的代码:

boolean needsWakeup=false;
synchronized(queue)
{
    if(queue.isEmpty())
         needsWakeup=true;
    queue.add(session);
}
if(needsWakeup)
   selector.wakeup();


在Mina 2.0里的优化是通过一个原子变量

 private final AtomicBoolean wakenUp = new AtomicBoolean(false);


在select之前将wakenUp设置为false,
wakenUp.set(false);
selector.select(timeout);
……

那么在wakeup方法调用之前通过cas来避免重复的唤醒:

 if (this.wakenUp.compareAndSet(false, true)) {
    selector.wakeup();
  }



0 请登录后投票
   发表时间:2010-04-22  
通过pipe写数据来唤醒线程,这在linux平台编程上是很常见的技巧,如memcached的多线程实现也是这样的,只不过因为windows平台没有pipe的支持,才使用一个tcp的loopack connection,因此会显得比较怪异。
0 请登录后投票
   发表时间:2010-04-22  
感谢楼上,我知道怎么优化了.
0 请登录后投票
   发表时间:2010-04-22  
dennis_zane 写道
通过pipe写数据来唤醒线程,这在linux平台编程上是很常见的技巧,如memcached的多线程实现也是这样的,只不过因为windows平台没有pipe的支持,才使用一个tcp的loopack connection,因此会显得比较怪异。


win下面 其实也有pipe..只是不怎么好用...
0 请登录后投票
   发表时间:2010-04-22  
mathgl 写道
dennis_zane 写道
通过pipe写数据来唤醒线程,这在linux平台编程上是很常见的技巧,如memcached的多线程实现也是这样的,只不过因为windows平台没有pipe的支持,才使用一个tcp的loopack connection,因此会显得比较怪异。


win下面 其实也有pipe..只是不怎么好用...


恩,主要还是windows上的pipe不能放入select的fd_set
0 请登录后投票
论坛首页 Java企业应用版

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