Эффективность while (true) ServerSocket Listen - PullRequest
9 голосов
/ 18 мая 2010

Мне интересно, если типичный while(true) цикл прослушивания ServerSocket занимает все ядро ​​для ожидания и принятия клиентского соединения (даже при реализации runnable и использовании Thread .start())

Я внедряю тип распределенного вычислительного кластера, и каждому компьютеру требуется каждое ядро ​​для вычислений. Главный узел должен взаимодействовать с этими компьютерами (вызывая статические методы, которые изменяют работу алгоритма).

Причина, по которой мне нужно использовать сокеты, связана с межплатформенными / кросс-языковыми возможностями. В некоторых случаях PHP будет вызывать эти статические методы Java.

Я использовал профилировщик Java (YourKit), и я вижу мой запущенный поток прослушивания ServerSocket, который никогда не спит и всегда работает. Есть ли лучший подход, чтобы делать то, что я хочу? Или производительность будет незначительной?

Пожалуйста, не стесняйтесь предлагать любые предложения, если вы можете придумать лучший способ (я пробовал RMI, но он не поддерживается на разных языках.

Спасибо всем

Ответы [ 4 ]

8 голосов
/ 18 мая 2010

Если вы имеете в виду что-то вроде этого:

while (true) {
  Socket socket = server.accept();
  /* Do something with socket... */
}

тогда нет, звонок на accept() не "берет все ядро". Это блокирующий вызов, который позволит планировать ЦП для другого потока, пока клиент фактически не подключится. Как только вызов accept() вернется, текущий поток будет запланирован для запуска и будет использовать ЦП, пока не заблокируется на accept() в следующей итерации цикла.

Чтобы избежать слишком большого количества невыполненных запросов на прослушивание других клиентов, другой поток обычно обрабатывает взаимодействие с недавно принятым Socket, оставляя один поток, чтобы сосредоточиться на принятии новых клиентов. Поток обработки сокетов может обрабатывать много сокетов, используя NIO, или он может быть выделен для одного сокета, который намного проще кодировать, но не может масштабироваться за многие сотни одновременных соединений.

5 голосов
/ 18 мая 2010

Возможно, вы захотите взглянуть на библиотеки Java 1.4 nio и, в частности, ServerSocketChannel. Я очень успешно использую это для реализации эффективного сервера, ключевые биты кода:

Selector selector = Selector.open();

ServerSocketChannel server= ServerSocketChannel.open();
server.socket().bind(new java.net.InetSocketAddress(port));
server.configureBlocking(false);
SelectionKey serverKey = server.register(selector, SelectionKey.OP_ACCEPT);

// start listening thread
new Thread(listener).start();

А слушатель - это просто цикл, который выполняется:

selector.select(1000); // listen for one second max
Set<SelectionKey> keys = selector.selectedKeys();

if (keys.size()>0) {
    handleKeys(keys);
}
3 голосов
/ 18 мая 2010

Я использовал профилировщик Java (YourKit), и я вижу, что мой запущенный поток прослушивания ServerSocket никогда не спит, и он всегда работает.

По сути, профилировщик вводит вас в заблуждение.

Полагаю, ваш код выглядит следующим образом:

ServerSocket server = ...
// configure server socket

try {
    while (true) {
        Socket socket = server.accept();
        // do something with socket (and close it afterwards!)
    }
} catch (InterruptedException ex) {
    // we're outta here!
}

Это не потребляет значительных ресурсов ЦП ... если вы не сделали что-то патологическое, например, вызов ServerSocket.setSoTimeout(int) с небольшим таймаутом.

0 голосов
/ 18 мая 2010

Дайте сердцу немного поспать. В свой метод Runnable добавьте что-то вроде

Thread.sleep(250); // milliseconds 

в каждом цикле.

Это должно значительно снизить нагрузку на процессор

Редактировать: плохая идея, смотреть комментарии, извините, моя вина


И: не используйте while (true). это ужасный дизайн, поскольку семантика предполагает, что в конечном итоге правда больше не будет правдой. Обычно вы хотите запросить некоторую переменную или атомарную переменную из основного потока

public class MyClass {

class MyRunnable implements Runnable {

    public void run() {
        while (MyClass.this.keepGoing.get()) {
            // listen();
            try {
                Thread.sleep(500);
            } catch (InterruptedException e) {
                // deal with exception
            }

        }
    }

}

private final AtomicBoolean keepGoing = new AtomicBoolean(true);

}

Таким образом, основной поток может остановить поток слушателя.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...