2010-07-14 51 views
1

我正在Java中实现一个非阻塞HTTP服务器,并决定使用纯Java NIO。我将一个NIO Selector与一个小线程池组合起来执行选择器指定的操作。Selector.select(timeout)x Selector.selectNow()

离开系统选择默认的选择和(在Linux 2.6 epoll和Mac OS雪狮子座KQueue测试)使用Selector.select(TIMEOUT);我得到监控状态的线程池(等待获取一个监听),而主线程(运行选择事件循环)保持始终运行。在某些情况下,监视器状态(等待获取监视器的时间)会浪费10秒以上。

使用下面的方法使主线程花费其大部分时间都在睡觉,更小(池线程几乎没有监控状态)和更高的吞吐量(1K请求每秒处理的):

while (true) { 
     Thread.sleep(IOLoop.SELECT_TIMEOUT); 
     if (selector.selectNow() == 0) 
      continue; 

     Iterator<SelectionKey> iter = selector.selectedKeys().iterator(); 
      //... 
      } 

任何人那里知道此决定的影响/风险,或者如何减轻/消除尝试获取对象所花费的时间使用带有超时选择器选择方法的监视器?

谢谢。

回答

1

选择器API和太阳的IMPL是可怕的。

该文档允许您在一个选择器的select()上阻塞多个线程,但没有关系。你应该只有一个线程在一个selector.select()上被阻塞。

而实际的impl只是在select()中做syncrhonized(this)来实现线程安全。

这就像过去的同步过去的矢量和散列表。

他们应该简单地暴露低级原始非阻塞方法,没有将它们包装在如此多的保姆抽象中 - 一般的程序员不会使用选择器,那些可以自己照顾自己的人。

+0

你会推荐什么? (我们不能考虑MINA,Netty,Grizzly等)。谢谢。 – paulosuzart 2010-07-14 20:05:10

+1

每个选择器应该有一个线程。那个线程select(),然后从选定的通道读取数据。解析数据,在你的情况下,HTTP请求也可以在同一个线程中执行。这听起来像是单线程编程,如果你只有一个CPU,这个表现很好。如果你有N个CPU,你可以有N个选择器,每个选择器有一个上述的线程。 – irreputable 2010-07-14 21:35:00

+0

我正在使用线程池来处理由select()返回的事件,就像我在问题2880443中所说的那样。 它需要一些工作来防止线程访问单线程选择器。就像取消密钥并在实际向线程分派事件之前执行下一次选择一样。 我也会尝试你的方法。谢谢! – paulosuzart 2010-07-15 13:00:19

0

睡觉,而不是使用超时只是浪费更多时间 - 你总是睡觉的睡眠时间间隔,而与超时你醒来时提前,如果有选择事件。

在某些情况下,显示器状态会浪费 超过10秒。

你是什么意思?

+0

yap EJP,现在我必须等待一段固定的时间。奇怪的是吞吐量更好,并且没有CancelledKeyException /浪费时间来获取池中线程的监视器。 问题已更新,以澄清显示器。 – paulosuzart 2010-07-14 02:04:47

+0

CancelledKeyException意味着您正在处理已被取消的密钥,通常是因为通道已关闭。您可以通过在选择器处理循环的头部测试key.isValid()来解决这个问题。坦率地说,你似乎有一些知之甚少的代码,并且你采用了糟糕的技术而不是合适的解决方案。 – EJP 2010-07-15 02:48:23