views:

113

answers:

2

Hi,

I'm implementing a Non-Blocking HTTP server in Java and decided to use pure Java NIO. I'm combining a NIO Selector with a small thread pool to perform the operations indicated by the selector.

Leaving the system choose the default selector (tested in Linux 2.6 epoll and Mac OS Snow Leo KQueue) and using Selector.select(TIMEOUT); I get the thread pool in Monitor state (waiting for acquire a Monitor) while the main thread (running the selector event loop) stay always running. In some cases the Monitor state (the time waiting for acquire a Monitor) wastes more than 10s.

Using the following approach causes the main thread spend most of its time sleeping, less (almost nothing Monitor state for pooled threads) and better throughput (1k requests handled per second):

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

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

Anyone there know the impacts/risks of this decision, or how to alleviate/eliminate the expended time trying to acquire an object Monitor using the selector select method with timeout?

Thanks.

A: 

Sleeping instead of using a timeout just wastes more time - you always sleep for the sleep interval, whereas with the timeout you wakeup early if there is a selection event.

In some cases the Monitor state wastes more than 10s.

What do you mean by that?

EJP
yap EJP, now I have to wait for a fixed period. The curious is a better throughput and no CancelledKeyException/Excessive time waste for acquire a monitor for threads in pool.Question Updated to clarify the Monitor.
paulosuzart
CancelledKeyException means that you are processing a key that has been cancelled, usually because the channel has been closed. You get around that by testing key.isValid() at the head of the selector processing loop. To be frank it seems that you have some poorly understood code and you've adopted poor technique instead of a proper solution.
EJP
+1  A: 

Selector api and sun's impl are horrible.

The document allows you to have multiple threads blocking on one selector's select(), but there is no point doing that. You should have only one thread blocked on one selector.select().

And the actual impl simply does syncrhonized(this) in select() to achieve thread safety.

It's like the Vector and Hashtable of the old days of excessive synchronization.

They should have simply exposed low level primitive non blocking methods, without wrapping them in so many nanny abstractions - average programmers won't use selectors, and those who do can take care of themselves.

irreputable
What would you recommend? (we cannot consider MINA, Netty, Grizzly, etc). thanks.
paulosuzart
you should have one thread per selector. that thread does select(), then reads data from selected channels. parsing data, in your case HTTP request, can also be carried out in the same thread. this all sounds like single thread programming, and if you have only one CPU, this performs well. if you have N CPUs, you can have N selectors, and each selector has one thread described above.
irreputable
I'm using pool of threads to handle events returned by select() like I say in question 2880443. It requires some work around to prevent thread access the single threaded selector. Like canceling the key and performing the next select before actually dispatch events to threads.I will try your approach too. Thanks!
paulosuzart
I'm still facing some issues if another thread tries to register a new/existing channel on the selector performing a select(timout); The second thread remains blocked until this time elapses. Even calling selector.wakeup() before register. Your approach should really be tested soon.
paulosuzart
A way to get over this issue is using a variable timeout for select(). I'm using a thread pool for handling events from selectedKeys. If there are any running thread in the pool, the timeout is the small it can (1ms or switch for selectNow instead of select(timeout)). It works very well although doesn't look good.
paulosuzart
yeah, the api sucks. workaround: you can have a queue in the select thread; the other thread puts the new channel in the queue, then call wakeup(). then the select thread wakes up from select(), it can examine the queue, and register new channels. that's just the beginning of the complexity.
irreputable
you must be sure you really need nio for solid reasons and you are ready to handle the complexity. it's a shame that java community is quite silent about its dark side, and a newbie after reasonable research could only conclude that nio is the obviously correct choice. read this: http://paultyma.blogspot.com/2008/03/writing-java-multithreaded-servers.html
irreputable