Улучшение производительности NIO по сравнению с традиционным IO в Java - PullRequest
22 голосов
/ 30 сентября 2011

Я видел много статей / блогов, в которых говорилось, что Java NIO - лучшее решение по сравнению с традиционным Java IO.

Но сегодня один из моих коллег показал мне этот блог http://mailinator.blogspot.com/2008/02/kill-myth-please-nio-is-not-faster-than.html. ЯИнтересно, проводил ли кто-нибудь из сообщества Java такой тип тестирования производительности Java NIO.

Ответы [ 10 ]

34 голосов
/ 30 сентября 2011

NIO vs IO - довольно интересная тема для обсуждения.

По моему опыту, это два разных инструмента для двух разных работ. Я слышал о том, что IO называют подходом «поток на клиента», а NIO - подходом «один поток для всех клиентов», и я считаю, что имена, хотя и не на 100% точные, подходят достаточно.

Реальная проблема с NIO и IO, на мой взгляд, связана с масштабируемостью.

Сетевой уровень NIO будет (должен?) Использовать один поток для обработки селектора и отправки заданий на чтение / запись / принятие другим потокам. Это позволяет потоку, обрабатывающему селектор («поток селектора»), ничего не делать, кроме этого. Это позволяет гораздо быстрее реагировать при работе с большим количеством клиентов (обратите внимание на отсутствие фактических чисел). Теперь, когда NIO начинает разваливаться, это когда сервер получает так много чтения / записи / принятия, что поток селектора постоянно работает. Любые дополнительные задания после этого и сервер начинает лагать. Кроме того, поскольку все задания чтения / записи / принятия обрабатываются потоком селектора, добавление дополнительных процессоров к миксу не приведет к повышению производительности.

Сетевой уровень ввода-вывода, вероятно, будет использовать подход 1 поток на сокет, включая сокет прослушивания. Таким образом, количество потоков прямо пропорционально количеству клиентов. При умеренном количестве клиентов этот подход работает очень хорошо. Стоимость, которую платят с помощью этого подхода, выражается в виде стоимости потока. если у вас есть 2000 клиентов, подключенных к серверу ... у вас есть по крайней мере 2001 потоков. Даже в четырехъядерном процессоре, по 6 ядер на машину, у вас есть только 24 обрабатывающих узла (48, если считать HyperThreading) для обработки этих потоков 2001 года. Создание всех этих потоков стоит времени и оперативной памяти процессора, но даже если вы используете пул потоков, вам все равно придется платить за переключение контекста процессоров при их перемещении из потока в поток. Это может стать очень уродливым при высоких нагрузках на сервер и, если не будет правильно закодировано, может привести к остановке всей машины. С другой стороны, добавление процессоров к машине в этом случае улучшит производительность.

Теперь все хорошо, но в резюме, потому что в моем описании нет цифр, помогающих принять решение о переходе на IO или NIO. Это связано с тем, что нужно учитывать еще больше переменных:

  • Время жизни клиента? Короткий или длинный?
  • Объем данных, ожидаемых на одного клиента? Много маленьких кусков или несколько огромных кусков?
  • Сколько клиентов предполагается подключить одновременно?
  • В какой ОС вы работаете и какую JVM используете? Оба фактора в потоке и расходы на опрос.

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

18 голосов
/ 30 сентября 2011

A быстрее, чем B , является часто очень упрощенным видом и иногда просто неправильно.

NIO не автоматически быстрее, чем обычный ввод-вывод.

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

Но NIO - это не волшебный переключатель «делай вещи быстрее», который нужно применять ко всему.

10 голосов
/ 12 февраля 2012

NIO используется не потому, что он быстрее , а потому, что он имеет лучшую масштабируемость , особенно при большом количестве клиентов.

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

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

NIO (None Blocking IO / Block IO , какой использовать ) использует ReactorШаблон для обработки событий ввода-вывода.В этом случае вы могли бы использовать один поток для блокировки / прослушивания | чтения | процесса | записи .Тогда блокирование клиентов (период ожидания) не будет влиять друг на друга.

Обратите внимание, что как IO, так и NIO могут использовать многопоточность для использования большего количества ресурсов ЦП, подробности см. В Введение Дуга Ли .

4 голосов
/ 30 сентября 2011

Проблема со статьей состоит в том, что она сравнивает блокирующий ввод-вывод с неблокирующим вводом-выводом. В моих собственных тестах сравнение блокирования ввода-вывода с блокировкой NIO (больше похоже на лайки) NIO работает на 30% быстрее.

Однако, если ваше приложение не является тривиальным, как прокси-сервер, оно вряд ли имеет значение. То, что делает приложение, гораздо важнее. И IO, и NIO были протестированы с количеством подключений до 10 000.

Если вы хотите супер быстрый ввод-вывод, вы можете использовать Asynch IO (Java 7+) с Infiniband (не дешево, но с меньшей задержкой)

4 голосов
/ 30 сентября 2011

Статьи, на которую вы ссылаетесь, три года.Он использовал Java 1.4.2 (4).

С тех пор Java 5, 6, а теперь и 7 отсутствуют.

Огромные изменения внутри JVM, а также библиотека классов сделали что-либонеобходимость делать бенчмаркинг 1.4.2 не имеет значения.

Если вы начнете копать, вы также заметите, что различие между java.io и java.nio не так уж и ясно.Многие из вызовов java.io теперь преобразуются в классы java.nio.

Но всякий раз, когда вы хотите повысить производительность, решение состоит не в том, чтобы просто что-то делать.Единственный способ узнать наверняка - это попробовать разные методы и измерить их, потому что то, что быстро для моего приложения, не обязательно так для вашего приложения, и наоборот.NIO может быть медленнее для некоторых приложений.Или это может быть решением проблем с производительностью.Скорее всего, это и то и другое.

2 голосов
/ 30 сентября 2011

Кроме того, AFAIK, Java IO был переписан для использования NIO под прикрытием (и NIO имеет больше функциональных возможностей). Микробенчмарки - это просто плохая идея, особенно когда они старые, как утверждает Лавинио.

1 голос
/ 16 февраля 2013

Java NIO и схема реактора не столько о самой производительности сети, сколько о преимуществах, которые однопоточная модель может предоставить системе с точки зрения производительности и простоты.И это, однопоточный подход, может привести к значительным улучшениям.Посмотрите здесь: Связь между сокетами с задержкой менее 2 микросекунд

1 голос
/ 11 июля 2012

Java NIO считается более быстрым, чем обычный IO, потому что:

  1. Java NIO поддерживает неблокирующий режим. Неблокируемый ввод-вывод выполняется быстрее блокирующего ввода-вывода, поскольку для него не требуется выделенный поток на соединение. Это может значительно улучшить масштабируемость, когда вам нужно обрабатывать много одновременных соединений, поскольку потоки не очень масштабируемы.

  2. Java NIO уменьшает копирование данных, поддерживая прямые буферы памяти. Можно читать и записывать сокеты NIO вообще без копирования данных. В традиционном Java IO данные копируются несколько раз между буферами сокетов и байтовыми массивами.

0 голосов
/ 01 октября 2011

Нет внутренней причины, по которой один быстрее другого.

Модель с одним подключением к потоку в настоящее время страдает от того факта, что поток Java имеет большие накладные расходы памяти - стек потоков предварительно выделен для фиксированного (и большого) размера. Это может быть и должно быть исправлено; тогда мы можем дешево создать сотни тысяч потоков.

0 голосов
/ 30 сентября 2011

Java IO содержит несколько конструкций и классов.Вы не можете сравнивать на таком общем уровне.В частности, NIO использует для отображения файлы с отображением в памяти - теоретически ожидается, что это будет немного быстрее, чем простое чтение файла BufferedInputStream.Однако, если вы сравните что-то вроде файла RandomAccess для чтения, то отображенный в память файл NIO будет быстрее lot .

...