Неблокирующий и асинхронный ввод-вывод Java с NIO и NIO.2 (JSR203) — реализации Reactor/Proactor

Итак, вот я читаю одну из моих любимых книг по шаблонам программного обеспечения (Pattern-Oriented Software Architecture — Patterns for Concurrent and Networked Objects), особенно разделы, посвященные шаблонам асинхронного ввода-вывода Proactor/Reactor. Я вижу, как с помощью выбираемых каналов я могу довольно легко реализовать механизм асинхронного ввода-вывода в стиле Reactor (и сделал это). Но я не вижу, как реализовать правильный механизм Proactor с неблокирующей записью. Это использует преимущества неблокирующих функций записи, управляемых ОС.

Функциональность, поддерживаемая специфическими для ОС вызовами, такими как GetQueuedCompletionStatus под Win32.

Я видел, что Java 7 вносит некоторые обновления в NIO с обработчиками асинхронного завершения (что, кажется, в правильном направлении). При этом... Учитывая отсутствие единой кроссплатформенной поддержки асинхронных операций, управляемых ОС (в частности, асинхронной записи), я предполагаю, что это квази-реализация, которая не использует встроенную поддержку ОС.

Итак, мои вопросы: возможна ли обработка ввода-вывода на основе proactor в Java таким образом, чтобы ее было выгодно использовать для конкретных сценариев; и, если Java NIO поддерживает обработку ввода-вывода на основе проактора (либо в Java 6, либо в Java 7), используется ли поддержка асинхронного ввода-вывода, управляемая ОС (т.е. обратные вызовы завершения из ОС)? Кроме того, если реализация выполняется исключительно внутри виртуальной машины, выигрыш в производительности настолько мал, что использование упреждающей обработки событий предлагает не что иное, как другой (возможно, более простой) способ создания программного обеспечения для параллельной обработки сети.

Для всех, кто интересуется упреждающей обработкой событий, вот хорошая статья, в которой описывается плюсы/минусы и сравнение как с традиционными моделями thread-per-connect, так и с реактивными моделями ввода-вывода.


person S73417H    schedule 03.04.2011    source источник
comment
Если вы действительно хотите знать, как выглядит реализация, вы можете скачать исходный код JDK 7 и посмотреть самостоятельно: openjdk.java.net/projects/jdk7   -  person Jesper    schedule 03.04.2011
comment
Хороший вопрос, Джеспер. Я приложу усилия, чтобы сделать это в ближайшее время!   -  person S73417H    schedule 05.04.2011


Ответы (4)


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

Возможна ли в Java обработка ввода-вывода на основе proactor таким образом, чтобы ее было выгодно использовать для конкретных сценариев.

В Java 1.4 введен неблокирующий ввод-вывод, который НЕ совпадает с асинхронным вводом-выводом. Java SE 7 представляет асинхронный ввод-вывод с JSR203, что делает возможными реализации обработки ввода-вывода в стиле proactor.

См. AsyncrhonousSocketChannel, AsynchronousServerSocketChannel

и, если Java NIO поддерживает обработку ввода-вывода на основе проактора (либо в Java 6, либо в Java 7), используется ли поддержка асинхронного ввода-вывода, управляемая ОС (т.е. обратные вызовы завершения из ОС)?

Читая спецификации JSR 203, обработчики завершения, использующие новые асинхронные каналы, определенно поддерживаются, и сообщается, что используются собственные функции ОС, но я еще не установил, в какой степени. Я могу продолжить это после анализа исходного кода Java 7 (если кто-то не опередит меня).

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

Мне не удалось найти каких-либо сравнений производительности новых функций асинхронного ввода-вывода в Java 7. Я уверен, что они станут доступны в ближайшем будущем.

Как всегда, когда предлагается несколько способов решения проблемы, на вопрос о том, какой подход лучше, почти всегда отвечают «зависит». Упреждающая обработка событий (с использованием обработчиков асинхронного завершения) включена в Java 7 и не может просто существовать без цели. Для некоторых приложений имеет смысл использовать такую ​​обработку ввода-вывода. Исторически сложилось так, что проактор хорошо применим на HTTP-сервере, где часто выдается много коротких запросов. Для более глубокого объяснения прочитайте это (приведено только для того, чтобы подчеркнуть преимущества proactor, поэтому попробуйте упускать из виду тот факт, что код примера написан на C++).

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

. . .

Кстати, я настоятельно рекомендую прочитать следующую презентацию о NIO, которая предлагает сравнение производительности между NIO и "традиционным" подходом. . Хотя я бы также посоветовал проявлять осторожность в отношении представленных результатов, поскольку реализация NIO в тесте была основана на библиотеке NBIO до Java 1.4, а не на реализации NIO, поставляемой в версии 1.4.

person S73417H    schedule 05.04.2011
comment
Я столкнулся с этим, пытаясь найти что-то в java, сравнимое с boost::asio. Мой вывод заключается в том, что сейчас ничего не существует, но что-то подобное может быть возможно с Java7. - person poindexter; 25.05.2011
comment
В качестве обновления: Java 1.4 NIO используется в Windows select, а Java 7 AIO использует в Windows IOCP, поэтому в Windows AIO определенно быстрее и масштабируемее. - person Kr0e; 21.05.2014

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

Блоки чтения, в которых нет данных для чтения. Это может быть большую часть времени. Однако блокировка записи при заполнении буферов происходит очень редко и часто указывает на медленное соединение или неисправный потребитель.

Если вам нужен неблокирующий ввод-вывод, сделайте это для чтения, а значит, и для записи.

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

person Peter Lawrey    schedule 03.04.2011
comment
Согласен, что для большинства решений механизм обработки ввода-вывода на основе реактора является наиболее подходящим. Но бывают обстоятельства, когда предпочтительна упреждающая обработка операций ввода-вывода (в частности, использование преимуществ упреждающей многоядерной обработки, предлагаемой базовой ОС). Поэтому я предполагаю, что мой вопрос на самом деле не относится к тому, необходим ли proactor или является ли он преимуществом в каком-либо конкретном сценарии, а скорее может ли это быть успешно выполнено с помощью Java, не будучи бессмысленным. - person S73417H; 05.04.2011
comment
Основная причина, по которой я подозреваю, что это бесполезно, заключается в том, что при сравнении блокирующего NIO с неблокирующим NIO вы можете получить значительно лучшую производительность с блокирующим (один поток на соединение) вводом-выводом до 1000 подключений. Я не проверял это на Windows, однако я думаю, вы должны предположить, что никакого улучшения производительности может и не быть. - person Peter Lawrey; 05.04.2011

одна из моих любимых книг по шаблонам программного обеспечения (Pattern-Oriented Software Architecture — Patterns for Concurrent and Networked Objects)

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

В настоящее время я считаю, что NIO уже является фреймворком и шаблоном проектирования.

person user207421    schedule 05.04.2011
comment
Имхо, он хорошо состарился. Неблокирующий ввод-вывод — это то, чего многие инженеры боятся или не замечают. В книге демонстрируется надежная конструкция NIO на C++, которая остается надежной и сегодня (у Boost/ACE есть реализации proactor и реактора). Рискуя звучать как торговец шаблонами, обработка ввода-вывода в стиле реактора и проактора — это то, что должен знать каждый инженер (особенно реактор). - person S73417H; 05.04.2011
comment
@ S73417H: кроме того, NIO рождается из select(), который рождается из одного потока на процесс. В настоящее время существует школа мысли, которая говорит, что теперь у нас есть потоки, которым вообще не нужен неблокирующий/мультиплексный ввод-вывод. И, попытавшись реализовать NIO-фреймворк общего назначения на основе Reactor, я должен был бы категорически не согласиться с тем, что это должен знать каждый инженер. NIO так сильно борется с Reactor, что у вас действительно нет другого выбора, кроме как придерживаться NIO. Фреймворки вокруг NIO, такие как Mina, на мой взгляд, не являются контрпримерами. - person user207421; 05.04.2011
comment
@EJP... Я должен с уважением не согласиться с твоим POV. Помимо производительности, NIO-фреймворки общего назначения, безусловно, позволяют лучше разделить задачи в сетевом коде. По моему опыту, если вы хорошо понимаете и используете эти фреймворки, разработчик может создавать гораздо более понятные, гибкие и тестируемые сетевые приложения. Далее, я не вижу, как НИО и реактор борются друг с другом. Я обнаружил, что реализовать реактор с помощью Java NIO довольно просто. Кроме того, в условиях, когда одновременно могут быть активны тысячи одновременных сетевых подключений, пул потоков с Reactor отлично работает. - person S73417H; 05.04.2011
comment
@ S73417H: реализовать Reactor с помощью NIO достаточно просто. Что сложно, так это построить фреймворк общего назначения поверх этого. Мои собственные попытки и попытки других, таких как Мина, меня не вдохновляют. Питер Лоури опубликовал результаты исследования либо здесь, либо на форумах Oracle Java, которые опровергают вашу последнюю точку зрения. - person user207421; 07.04.2011

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

Не изобретайте его заново, просто используйте его, потому что вы не сможете превзойти его производительность — а это, в конце концов, любой, кто пытается избежать блокировки ввода-вывода — с чистым решением Java, поскольку вы не получаете доступ к не- блокирующие/асинхронные функции базовой ОС. Но NIO и NIO2 используют их, что делает их быстрыми.

person Evgeniy Berezovsky    schedule 27.05.2015
comment
@EJP Я полностью согласен с вашим ответом, просто хотел добавить немного плоти (которую я только что обнаружил - так что я не забуду). - person Evgeniy Berezovsky; 27.05.2015
comment
@EJP OT: Я щелкнул ссылку telekinesis.com.au в вашем профиле, пытаясь узнать, что представляет собой музыкант в вашем профиле, но... ссылка мертва! Тем не менее, он живет в машине обратного пути, и ваше резюме рассказало мне все и даже больше, чем я хотел знать. Я надеюсь, что раздел здоровье не пришлось пересматривать. Еще в 2007 году вы описали это так: Excellent general health; excellent fitness; non-smoker. Если бы я не жил в паре миль к северу от Азии, я бы с удовольствием выпил пива. - person Evgeniy Berezovsky; 27.05.2015