Search
Write a publication
Pull to refresh
2
0
Александр Васильев @a_a_vasiljev

ведущий разработчик

Send message

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

Тезисы доклада Андрея:

  1. реактивные стримы не имеют отношения к реактивному программированию;

  2. на бэкэнде не бывает реактивного программирования;

  3. Loom сдвигает точку Нетфликса очень сильно вправо;

  4. принятие Loom не затронет [реактивные] стримы.

Считаю, что тезисы Андрея аргументированы и весомы, его точка зрения имеет право на существование.

Мычка ссылается на доклад Олега Докуки и Андрея Родионова, хотя тот имеет небольшое отношение к Loom (согласен с Андреем).

Кроме того, Мычка ссылается другие интересные материалы:

Брайан Гётс "Loom убьёт реактивное программирование"

Эрик Мейер "Что значит быть реактивным?"
Мейер - фантастический докладчик. Рассматривает реактивное программирование в аспекте сайдэффектов. Хотя напрямую к Loom его доклад отношения не имеет, идеи там высказаны глубокие. Интересно будет взглянуть на проект Loom, используя подход Мейера.

И да, и нет. "Да", потому что добавляется возможность перехода на легковесные программные потоки. То есть работать будет (семантика) похоже на async / await. "Нет", потому что язык расширять (менять синтаксис) не будут. Обойдутся изменениями библиотечных функций. Старые-добрые Джава экзекуторы, форки и джойны без асинков и эвэйтов.

Дадут. А ведь можно запустить 100 новых тредов и в каждом их них сделать вызов. И дождаться завершения 100 тредов в треде-родителе. Понятно, эту схему придётся усложнить с учётом дросселирования, переотправки кусочков в случае сбоя и отмены пересылки всего документа в каждом из дочерних тредов.

Между прочим, интересно, поддерживаете ли вы в своём приложении отмену отправки документа и остановку пересылки его кусочков? Это одна из центральных тем второй части заметки.

Пардон, Loom к нам только осенью в Java 19 приедет, да и то в виде превью фичи. А доклад состоится уже на днях и в готовом к употреблению виде. Ну как его не порекомендовать?

Это 100% корректный подход, которым вы достигаете нужного вам результата. Прекрасно. Рискну предположить, что поддержка кода вашего приложения стоит так много, как нам об этом и рассказывает Нуркевич.

Во-первых, подчеркну ещё раз, не с "синхронной функцией", а с асинхронной. И, понятно, эта функция должна быть идемпотентна. И её нужно вызывать при старте приложения для недообработанных документов по-новой.

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

Давайте пойдём сверху вниз? Допустим, у вас имеется чёрный ящик, внутри которого реализована функциональность:

  1. отсылка документа по кусочкам с подтверждением приёма каждого кусочка;

  2. получение уведомления о приёме документа с ЭЦП;

  3. получение результатов запроса.

Ну так схема 1-2-3-4-5 из комментария выше подходит. На шаге 2 (отправитель отправляет запрос) посылаем событие в чёрный ящик "начать отсылку докумена по кусочкам". На шаге 4 из комментария выше чёрный ящик, когда получил результат запроса, положит его в контейнер. В результате на самом верхнем уровне чёрный ящик вместе со всей своей головоломной машинерией скрыт за фасадом "школьной" функции "удалённо обработать документ".

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

А где вы храните высокоуровневый контекст: в БД (на диске) или в оперативной памяти?

Можно и с событиями повозиться. Это же задача синхронизации. Для её решения понадобятся дополнительные примитивы. Например, Future / Deferred.

  1. Отправитель формирует Future-контейнер для ожидания результата и кладёт контейнер в словарь по идентификатору запроса.

  2. Отправитель отправляет запрос.

  3. Отправитель засыпает на Future.

  4. Поток-получатель находит по идентификатору запроса в словаре контейнер и помещает туда ответ.

  5. Отправитель просыпается и продолжает обработку результата.

Код отправителя последовательный, в этом он не отличается от синхронного.

По описанному процессу спорить не о чем. Всё так и есть. Два встречных асинхронных потока, и так далее.

Не вижу способа избавиться от асинхронности и сохранить эффективность.

Задачи избавиться от асинхронности не стоит. И обработка сообщений, и треды (в том числе легковесные треды) -- это разные способы организации асинхронной работы.

В целом согласен, прокомментирую.

нет никакой проблемы создать более 10К тредов

ОК. Интересно, между прочим -- зачем?

на одном хосте нужно обслужить 10К запросов одновременно.

Да. В этом тонкость сообщения Нуркевича. Когда проект разрастается так, что нагрузка превышает некоторый порог (и число 10k тут условно, согласен), тогда блокирующий подход перестаёт быть адекватным. А до того момента блокирующий подход ого-го какой адекватный.

решать с помощью дополнительных хостов

Так о том и речь. Смотри "стоимость железа".

вы упретесь в ограничение количества локальных портов

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

Здесь нас (разработчиков) ждёт несколько сюрпризов.

Про это -- только в 73-й части заметки. Только, боюсь, здесь её опубликовать не получится. Меня и так на Хабре уже почти забанили.

Всё так. Сергей Куксенко измерял выигрыш в производительности и получал 2-3 раза, если не ошибаюсь. Иван Углянский тоже что-то намерил и расскажет на JPoint (рекомендую). Кто-то говорит о порядках в отдельных сценариях. Всё может быть.

Вместе с этим кричащая разница -- это максимально возможное количество тредов, системных и виртуальных. Она оценивается в два с половиной порядка. Триста раз. То есть виртуальных потоков можно создать даже не сотни тысяч, как предполагал уважаемый pin2t, а миллионы. И JVM потянет.

Нуркевич в своём докладе (ссылка в заметке) упоминает, что "решил проблему 10k соединений". Про что это? Блокирующий (классический) подход предполагает, что каждое новое установленное соединение обрабатывается одним тредом. А в JDK жёсткое соответствие: один JDK-тред привязан одному системному треду, и наоборот. Вот 10k системных тредов уже слишком много для ОС. Приложение падает. Скорее всего, оно упадёт ещё до 10k. Поэтому несколько сотен тысяч -- вряд ли.

Проблема 10k решается неблокирующим подходом. Сейчас таких в мейнстриме два: реактивный и легковесные треды (фибры, горутины, корутины, виртуальные треды и так далее).


Об этом -- в следующей части заметки.

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

Заметка Натаниэля, с моей точки зрения, ценна тем, что тут автор чётко формулирует новую концепцию, опуская детали реализации и другие несущественные подробности. С деталями реализации можно познакомиться, перейдя по ссылкам на страничке-агрегаторе.

Information

Rating
Does not participate
Location
Новосибирск, Новосибирская обл., Россия
Works in
Registered
Activity