Рубрики
Без рубрики

Объясните Неблокирующий ввод-вывод Как будто мне Пять лет

В этом посте мы проиллюстрируем концепцию неблокирующего ввода-вывода простой аналогией: ваша собственная фабрика таблиц. Помеченный java, асинхронный, explainlikeimfive, для начинающих.

Десять лет назад произошел серьезный сдвиг в области разработки сетевых приложений. В 2009 году Райан Даль изобрел Node.js потому что его не устраивали ограниченные возможности популярного HTTP-сервера Apache для обработки тысяч одновременных подключений. Тот Node.js проект объединил движок JavaScript, цикл событий и уровень ввода-вывода. Обычно его называют неблокирующим веб-сервером.

Идея неблокирующего ввода-вывода в сочетании с циклом событий не нова. Сообщество Java добавило NIO модуль для J2SE 1.4 уже в 2002 году. Netty , неблокирующая платформа клиент-сервер ввода-вывода для разработки сетевых приложений Java, активно разрабатывается с 2004 года. Операционные системы предлагают функциональные возможности для получения уведомлений, как только сокет становится доступным для чтения или записи, даже с тех пор, как это произошло.

В настоящее время вы часто слышите или читаете комментарии типа “X – это неблокирующая, управляемая событиями, масштабируемая [вставьте здесь еще одно модное слово] структура”. Но что это значит и почему это полезно? Остальная часть этого поста структурирована следующим образом. В следующем разделе будет проиллюстрирована концепция неблокирующего ввода-вывода с помощью простой аналогии. После этого мы обсудим преимущества и недостатки неблокирующего ввода-вывода. Следующий раздел позволяет нам взглянуть на то, как неблокирующий ввод-вывод реализован в различных операционных системах. Мы завершим этот пост, высказав несколько заключительных мыслей.

Ваш Первый сотрудник и Рабочий стол

Представьте, что вы начинаете бизнес по производству таблиц. Вы арендуете небольшое здание и покупаете один верстак, потому что у вас есть только один сотрудник, назовем его Джордж. Утром Джордж входит в здание, подходит к рабочему столу и выбирает новый заказ из папки “Входящие”.

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

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

Несколько Сотрудников, Один Рабочий Стол

Вам интересно, могли бы вы повысить производительность, убедив Джорджа поработать над чем-то другим, пока доставляются материалы. Может пройти несколько дней, прежде чем прибудет новая доставка, а Джордж будет просто стоять и ничего не делать. Вы предлагаете ему свой новый план, но он отвечает: “Я действительно плохо переключаюсь с контекста, босс. Но я был бы счастлив вернуться домой и ничего там не делать так что я, по крайней мере, не загораживаю рабочий стол!”.

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

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

Многозадачные, Неблокирующие Сотрудники

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

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

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

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

Использование неблокирующего ввода-вывода в правильной ситуации улучшит пропускную способность, задержку и/или быстродействие вашего приложения. Это также позволяет вам работать с одним потоком, потенциально избавляясь от синхронизации между потоками и всех проблем, связанных с этим. Node.js является однопоточным, но может без проблем обрабатывать миллионы подключений с парой ГБ оперативной памяти.

Распространенное заблуждение заключается в том, что неблокирующий ввод-вывод означает быстрый ввод-вывод. Просто потому, что ваш ввод-вывод не блокирует ваш поток, он не выполняется быстрее. Как обычно, серебряной пули нет, а есть только компромиссы. Есть хороший пост в блоге Техсоло обсуждение преимуществ и недостатков различных концепций по этой теме.

Существует множество различных форм и реализаций неблокирующего ввода-вывода. Однако все основные операционные системы имеют встроенные функции ядра, которые можно использовать для выполнения неблокирующего ввода-вывода./|epoll обычно используется в системах Linux и был вдохновлен kqueue ( исследовательский документ ), который доступен в системах на базе BSD (например, Mac OS X).

При использовании Java разработчик может полагаться на Java NIO. В большинстве реализаций JVM вы можете ожидать, что Java NIO будет использовать эти функции ядра, если это применимо. Однако есть некоторые тонкости, когда дело доходит до деталей. Поскольку API Java NIO достаточно универсален для работы во всех операционных системах, он не может использовать некоторые расширенные функции, которые отдельные реализации, такие как эполл или kqueue предоставить. Это очень похоже на базовую семантику опроса.

Таким образом, если вы ищете немного дополнительной гибкости или производительности, вы можете напрямую переключиться на собственный транспорт. Netty , одна из лучших платформ сетевых приложений на JVM, поддерживает как транспорт Java NIO, так и собственные библиотеки для Linux и Mac OS X.

Конечно, большую часть времени вы не собираетесь напрямую работать с Java NIO или Netty, а используете какую-либо платформу веб-приложений. Некоторые фреймворки позволят вам в некоторой степени настроить сетевой уровень. Например, в Vert.x вы можете выбрать, хотите ли вы использовать собственный транспорт, если это применимо, и он предлагает

Термин “неблокирующий” используется многими различными способами и контекстами. В этом посте мы сосредоточились на неблокирующем вводе-выводе, который относится к потокам, не ожидающим завершения операций ввода-вывода. Однако иногда люди называют API-интерфейсы неблокирующими только потому, что они не блокируют текущий поток. Но это не обязательно означает, что они выполняют неблокирующий ввод-вывод.

Возьмем в качестве примера JDBC. JDBC блокирует по определению. Однако существует клиент JDBC , который имеет асинхронный API. Блокирует ли он ваш поток во время ожидания ответа базы данных? Нет! Но, как я уже упоминал ранее, JDBC блокирует по определению, так кто же блокирует? Хитрость здесь в том, чтобы просто создать второй пул потоков, который будет принимать запросы JDBC и блокировать вместо вашего основного потока.

Почему это полезно? Это позволяет вам продолжать выполнять свою основную работу, например, отвечать на HTTP-запросы. Если не для каждого запроса требуется подключение JDBC, вы все равно можете отвечать на них с помощью основного потока, пока ваш пул потоков заблокирован. Это хорошо, но все еще блокирует ввод-вывод, и вы столкнетесь с узкими местами, как только ваша работа будет связана связью JDBC.

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

Изображение на обложке Пол Энглфилд

Оригинал: “https://dev.to/frosnerd/explain-non-blocking-i-o-like-i-m-five-2a5f”