Is it beneficial to distribute incoming connections among n threads, each with its own independent NIO Selector
, where n is, say, the number of cores in the server? Suppose I'm writing a server, which should handle a number of client connections. I could have something like:
selector.select();
Iterator<SelectionKey> i = selector.selectedKeys().iterator();
while (i.hasNext()) {
SelectionKey key = i.next();
i.remove();
if (!key.isValid())
continue;
if (key.isAcceptable()) {
// get one of the n selectors (I'd have one per core)
Selector chosenSelector = getRandomSelector();
// delegate the new connection to the chosen selector
SocketChannel newChannel = key.channel.accept();
newChannel.configureBlocking(false);
newChannel.register(chosenSelector, SelectionKey.OP_READ);
}
}
Do you guys think this makes sense? I mean, running n threads, each with a different selector? Or should I just stick to having one single selector thread that handles OP_READ for all connections? Or maybe something else?
Multiple threads accessing shared data simultaneously may lead to a timing dependent error known as data race condition. Data races may be hidden in the code without interfering or harming the program execution until the moment when threads are scheduled in a scenario (the condition) that break the program execution.
Many threads can run in a single process and each thread must be part of a process as it cannot exist on its own.
A selector provides a mechanism for monitoring one or more NIO channels and recognizing when one or more become available for data transfer. This way, a single thread can be used for managing multiple channels, and thus multiple network connections.
select. Selects a set of keys whose corresponding channels are ready for I/O operations. This method performs a blocking selection operation. It returns only after at least one channel is selected, this selector's wakeup method is invoked, or the current thread is interrupted, whichever comes first.
No it is not beneficial, as the relation of code that needs to be processed vs. the time it takes for the IO operations is negligible. Especially if you consider the extra time you would need for the synchronization of fragmented data. It is however beneficial to have the processing of the received data done in separate threads.
So basically: have a single-threaded selector loop that copies the data from one buffer into a task-buffer for further processing in a separate thread, then launch a Runnable with that task-buffer in an Executor to process that copied data.
This is exactly what Netty does. It uses N threads calling Selector.select()
where N = (num available CPUs * 2) It is multiplied by 2 because of hyperthreading. This is the parent EventLoop which is considered the "acceptor eventloop" for accepting socket connections.
Then there is the child EventLoop of thread workers
Suggest you have a look at NioEventLoopGroup
-class
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With