Как стать автором
Обновить

NIO: между Сциллой и Харибдой?

Время на прочтение 5 мин
Количество просмотров 7.2K
Одним из широко освещаемых свойств фреймворка java.NIO является неблокируемость, что означает спо­соб­ность к параллельному выполнению операций ввода-вывода и вычислений. Если приложение, запросившее чтение файла, имеет вычислительную задачу, которую можно обработать до получения данных из файла, то становится возможным одновременное выполнение этих операций. В случае отложенной записи, возможностей для параллелизма еще больше, так как при записи, в отличие от чтения, приложение не ожидает поступления данных.

Примечание. Хотелось бы озаглавить эту статью «NIO: производительность или и совместимость?», но в силу известных ограничений приходится цитировать имена этих древних греческих старух.

Фактором успеха здесь является аппаратная поддержка. Контроллеры mass storage устройств, такие как SATA AHCI (Advanced Host Controller Interface) и NVMe (Non-Volatile Memory Interface for PCI Express) способны обрабатывать достаточно длин­ные последовательности операций ввода-вывода и перемещать данные между оперативной памятью и нако­пи­те­лем в режиме bus-master, без участия программы, выполняемой центральным процессором.

Список команд, формируемый драйвером AHCI в оперативной памяти и аппаратно интерпретируемый контроллером

Рис.1 Список команд, формируемый драйвером AHCI в оперативной памяти и аппаратно интерпретируемый контроллером, может содержать до 32 дескрипторов операций ввода-вывода. Иллюстрация из документа AHCI Specification

Противоречия и решения


Здесь мы подходим к еще одной, менее очевидной, но при этом очень важной характеристике фреймворка NIO, в основе которого два взаимно-противоречивых критерия:

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


Java Native Interface


Одним из альтернативных решений является сопряжение Java-классов и библиотек, написанных на C или ассемблере. Здесь нельзя не упомянуть нативные классы, реализующие интерфейс JNI (Java Native Interface), основанный на классических конвенциях вызова, стандартизуемых для каждой операционной системы и дополняемых механизмом, обеспечивающим взаимодействие JVM и нативного кода. Кстати, овладев технологией JNI, можно получить доступ к указателям, отсутствие которых в Java, иногда доставляет неудобство.

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

Надо признать, есть ситуации, когда применение JNI необходимо. Например, поддержка некоторых специальных устройств, таких как аппаратный генератор случайных чисел.

NIO


Как оказалось, высокопроизводительный код можно разработать и на Java, если оптимально спроектировать систему абстракций, инкапсулирующих аппаратные ресурсы платформы.

Рассмотрим операцию чтения файла с диска. Очевидно наличие двух участников процесса: источник данных (накопитель или файл) и получатель (буфер в оперативной памяти). Все сказанное ниже, справедливо и для записи файла на диск, отличается только направление передачи информации, источник и получатель меняются местами.

Для пользовательских приложений, накопитель или файл представлен функциями ОС API дискового ввода-вывода. Не будем рассматривать возможность прямого программирования регистров контроллера дисков пользовательским приложением, канувшую в прошлое со времен MS-DOS, из очевидных соображений совместимости и безопасности.

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

Итак, рассматриваемые объекты аппаратной платформы, это:

  • Канал связи с накопителем или файлом (ОС API).
  • Диапазон оперативной памяти, буфер.

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

Конечно, подобный инструмент не может быть реализован без низкоуровневого аппаратно-зависимого программирования. Мы говорим лишь о том, что применение этого инструмента избавляет прикладного программиста от такой необходимости.

Утилита NIOBench


Утилита NIOBench, разработанная IC Book Labs и предназначенная для измерения производительности mass storage подсистемы, иллюстрирует сказанное, используя каналы и буферы при выполнении файловых операций.

Утилита NIOBench, вывод результатов измерения скорости чтения, записи и копирования файлов на жестком диске

Рис.2 Утилита NIOBench, вывод результатов измерения скорости чтения, записи и копирования файлов на жестком диске ноутбука ASUS N750JK (при обработке данных используется медиана и среднее арифметическое)

Текстовый рапорт утилиты NIOBench с детальным протоколированием результатов

Рис.3 Текстовый рапорт утилиты NIOBench с детальным протоколированием результатов: очевидно влияние кэширования

Методы ввода-вывода, в частности операции чтения, записи и копирования файлов, являющиеся объектом бенчмарок, основаны на следующих архитектурных элементах.

  • Объект FileChannel соответствует каналу, созданному на основе читаемого или записываемого файла. Наряду с простейшими операциями чтения и записи, поддерживаются методы transferTo(), transferFrom(), источником и получателем для которых могут быть объекты файловой системы. Такая особенность очень важна, поскольку позволяет копировать содержимое файлов одним java-оператором, изящно избавляясь от лишних пересылок данных между несколькими буферами. Надо сознаться, что эффективность оптимизации методов копирования, характерная для фреймворка NIO, сыграла злую шутку в процессе разработки и отладки бенчмарок: измеренная скорость копирования иногда оказывалась выше скорости записи.

  • Объект Buffer соответствует диапазону оперативной памяти. При всей очевидности этого понятия, отметим, что для минимизации количества транзитных перемещений данных, рекомендуется создавать прямой буфер, используя метод ByteBuffer.allocateDirect();

Несоблюдение этой рекомендации может привести к снижению производительности, обусловленному необходимостью преобразования Java-абстракций в нативные объекты, передаваемые на обработку функциям ОС API. Интерфейс JNI также используется в проекте NIOBench, для подключения библиотек поддержки аппаратного генератора случайных чисел на основе процессорной инструкции RDRAND (статья об этом «Java-бенчмарки: случайные паттерны и закономерные результаты» в процессе написания).

Резюме


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

Вместе с тем, никакого чуда не произошло, и низкоуровневая работа, от которой любой фреймворк осво­бо­жда­ет прикладных программистов, всего лишь переносится на разработчиков фреймворка и программистов сис­тем­ных…

Ссылки


Теги:
Хабы:
+7
Комментарии 18
Комментарии Комментарии 18

Публикации

Истории

Работа

Java разработчик
346 вакансий

Ближайшие события

PG Bootcamp 2024
Дата 16 апреля
Время 09:30 – 21:00
Место
Минск Онлайн
EvaConf 2024
Дата 16 апреля
Время 11:00 – 16:00
Место
Москва Онлайн
Weekend Offer в AliExpress
Дата 20 – 21 апреля
Время 10:00 – 20:00
Место
Онлайн