Selector.select(время ожидания) x Selector.selectNow()

Я реализую неблокирующий HTTP-сервер на Java и решил использовать чистый Java NIO. Я объединяю селектор NIO с небольшим пулом потоков для выполнения операций, указанных селектором.

Покинув систему, выберите селектор по умолчанию (проверено в Linux 2.6 epoll и Mac OS Snow Leo KQueue) и используя Selector.select(TIMEOUT); Я получаю пул потоков в состоянии монитора (ожидая получения монитора), в то время как основной поток (запускающий цикл событий селектора) остается всегда запущенным. В некоторых случаях состояние монитора (время ожидания получения монитора) занимает более 10 секунд.

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

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

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

Кто-нибудь знает о последствиях/рисках этого решения или о том, как облегчить/устранить затраченное время на попытку получить монитор объекта с помощью метода выбора селектора с тайм-аутом?

Спасибо.


person paulosuzart    schedule 14.07.2010    source источник


Ответы (2)


Селектор API и реализация Sun ужасны.

Документ позволяет вам блокировать несколько потоков в одном селекторе select(), но в этом нет смысла. У вас должен быть заблокирован только один поток на одном selector.select().

И фактический импл просто выполняет syncrhonized(this) в select() для обеспечения безопасности потоков.

Это как Vector и Hashtable старых дней чрезмерной синхронизации.

Они должны были просто показать низкоуровневые примитивные неблокирующие методы, не оборачивая их таким количеством няньских абстракций - обычные программисты не будут использовать селекторы, а те, кто их использует, могут позаботиться о себе сами.

person irreputable    schedule 14.07.2010
comment
Чтобы вы посоветовали? (Мы не можем рассматривать MINA, Netty, Grizzly и т.д.). Спасибо. - person paulosuzart; 15.07.2010
comment
у вас должен быть один поток на селектор. этот поток делает select(), а затем считывает данные из выбранных каналов. синтаксический анализ данных, в вашем случае HTTP-запрос, также может выполняться в том же потоке. все это звучит как однопоточное программирование, и если у вас только один ЦП, это работает хорошо. если у вас N ЦП, у вас может быть N селекторов, и каждый селектор имеет один поток, описанный выше. - person irreputable; 15.07.2010
comment
Я использую пул потоков для обработки событий, возвращаемых select(), как я сказал в вопросе 2880443. Требуется некоторая работа, чтобы предотвратить доступ потока к однопоточному селектору. Например, отмена ключа и выполнение следующего выбора перед фактической отправкой событий в потоки. Я тоже попробую ваш подход. Спасибо! - person paulosuzart; 15.07.2010
comment
Я все еще сталкиваюсь с некоторыми проблемами, если другой поток пытается зарегистрировать новый/существующий канал в селекторе, выполняющем select(timout); Второй поток остается заблокированным, пока не истечет это время. Даже вызов selector.wakeup() перед регистрацией. Ваш подход действительно должен быть проверен в ближайшее время. - person paulosuzart; 15.07.2010
comment
Способ решить эту проблему — использовать переменный тайм-аут для select(). Я использую пул потоков для обработки событий от selectedKeys. Если в пуле есть какой-либо запущенный поток, тайм-аут будет минимальным (1 мс или переключатель для selectNow вместо select (тайм-аут)). Он работает очень хорошо, хотя выглядит не очень хорошо. - person paulosuzart; 15.07.2010
comment
да, апи отстой. обходной путь: у вас может быть очередь в выбранном потоке; другой поток помещает новый канал в очередь, а затем вызывает wakeup(). затем поток select просыпается из select(), он может проверить очередь и зарегистрировать новые каналы. это только начало сложности. - person irreputable; 15.07.2010
comment
вы должны быть уверены, что вам действительно нужен nio по веским причинам, и вы готовы справиться со сложностью. обидно, что java-сообщество довольно умалчивает о его темной стороне, и новичок после разумных исследований мог сделать только вывод, что nio — заведомо правильный выбор. прочитайте это: paultyma.blogspot.com/2008/03/< /а> - person irreputable; 15.07.2010

Сон вместо использования тайм-аута просто тратит больше времени — вы всегда спите в течение интервала сна, тогда как с тайм-аутом вы просыпаетесь раньше, если есть событие выбора.

В некоторых случаях состояние монитора занимает более 10 секунд.

Что ты имеешь в виду?

person user207421    schedule 14.07.2010
comment
тявкать EJP, теперь я должен ждать фиксированный период. Любопытно, что это лучшая пропускная способность и отсутствие CancelledKeyException / чрезмерной траты времени на получение монитора для потоков в пуле. Вопрос Обновлен для уточнения Монитора. - person paulosuzart; 14.07.2010
comment
CancelledKeyException означает, что вы обрабатываете ключ, который был отменен, обычно потому, что канал был закрыт. Вы можете обойти это, проверив key.isValid() в начале цикла обработки селектора. Честно говоря, кажется, что у вас есть какой-то плохо понятый код, и вы приняли плохую технику вместо правильного решения. - person user207421; 15.07.2010