Преимущества / недостатки реактивного программирования

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

Есть ли какое-либо конкретное сравнение между реактивным программированием и императивным программированием в веб-приложениях?

Насколько прирост производительности и пропускной способности достигается за счет использования реактивного программирования по сравнению с нереактивным программированием?

Также каковы преимущества и недостатки реактивного программирования?

Есть ли какой-нибудь статистический ориентир?


person prranay    schedule 06.02.2017    source источник
comment
Я понимаю, что реактивное кодирование позволяет лучше использовать процессор по сравнению с однопоточным исполнением. Это не то, как это работает. Вы правильно поняли в первом предложении: Стиль кодирования.   -  person a better oliver    schedule 20.04.2018
comment
В этом посте рассказывается о плюсах и минусах реактивного программирования mydaytodo.com/pros-cons-of -реактивное программирование   -  person cptdanko    schedule 01.05.2021


Ответы (6)


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

Помимо этого, вы можете использовать обратные вызовы, чтобы сделать то же самое. Вы можете выполнять асинхронный вызов, используя обратные вызовы. Но если вы это сделаете, иногда вы можете столкнуться с адом обратного вызова. Наличие одного обратного вызова внутри другого приводит к очень сложным кодам, которые очень трудно поддерживать. С другой стороны, RxJava предоставляет вам возможность писать асинхронный код, который намного проще, удобнее и удобнее для чтения. Также RxJava предоставляет вам множество мощных операторов, таких как Map, Zip и т. Д., Которые делают ваш код намного более простым, одновременно повышая производительность за счет параллельного выполнения различных задач, которые не зависят друг от друга.

RxJava не является еще одной реализацией Observer с набором операторов, а дает вам хорошую обработку ошибок и механизмы повтора, которые действительно удобны.

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

Обновить

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

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

Вот некоторые свойства реактивных систем: управляемость событиями, масштабируемость, отказоустойчивость, отзывчивость.

Когда дело доходит до RxJava, он предлагает программисту две основные возможности. Во-первых, он предлагает хороший составной API с использованием богатого набора операторов, таких как zip, concat, map и т. Д. Это дает более простой и читаемый код. Когда дело доходит до кода, читаемость и простота - важнейшие свойства. Во-вторых, он предоставляет отличные абстракции, которые делают параллелизм декларативным.

Популярное заблуждение состоит в том, что Rx по умолчанию является многопоточным. Если честно, Rx по умолчанию однопоточный. Если вы хотите делать что-то асинхронно, вы должны указать это явно, используя операторы subscribeOn и observeOn, передав соответствующие планировщики. RxJava предоставляет пулы потоков для выполнения асинхронных задач. Есть много планировщиков, таких как ввод-вывод, вычисление и так далее. Планировщик ввода-вывода, как следует из названия, лучше всего подходит для задач с интенсивным вводом-выводом, таких как сетевые вызовы и т. Д. Напротив, планировщик вычислений хорош для более интенсивных вычислительных задач. Вы также можете подключить свои собственные службы Executor к RxJava. Встроенные планировщики в основном помогают вам избавиться от поддержки ваших собственных служб Executor, делая ваш код более простым.

Напоследок пару слов о подписке и наблюдении

В мире Rx обычно есть две вещи, для которых вы хотите контролировать модель параллелизма:

  1. Вызов подписки
  2. Наблюдение за уведомлениями

SubscribeOn: укажите планировщик, на котором будет работать Observable.

ObserveOn: укажите планировщик, на котором наблюдатель будет наблюдать за этим Observable

person Ravindra Ranwala    schedule 06.02.2017

Недостатки

  • Более интенсивный объем памяти для хранения потоков данных в большинстве случаев (поскольку он основан на потоках с течением времени).
  • С самого начала может показаться необычным учиться (нужно, чтобы все было потоком).
  • Большинство сложностей приходится решать во время объявления новых услуг.
  • Отсутствие хороших и простых ресурсов для изучения.

  • Часто путают с эквивалентом функционального реактивного программирования.

person Krishna Ganeriwal    schedule 29.08.2017
comment
В чем разница между реактивным программированием и функциональным реактивным программированием? Какие качества вы считаете разными? - person Noel Yap; 28.10.2018
comment
если все представляет собой поток с большим количеством операторов, его может быть труднее понять, чем простой императивный код. - person filthy_wizard; 03.01.2019
comment
@NovemberYankee, если честно, для этого понадобится отдельный пост. FRP - это своего рода супернабор реактивного программирования, и способы выполнения действий с использованием FRP различаются способами выполнения одной и той же операции с помощью реактивного программирования. Чистые функции и т. Д. Входят в картину с FRP, что не является необходимостью при реактивном программировании. - person Krishna Ganeriwal; 04.01.2019
comment
@filthy_wizard. Как я уже упоминал, сначала может быть трудно обдумать, но эти операторы упрощают и сокращают объем кода для многих вещей, которые в противном случае вам пришлось бы делать самостоятельно. - person Krishna Ganeriwal; 04.01.2019
comment
временами это полезно. Я бы не стал убивать с большим количеством операторов. это отнимает у читабильности. я хочу, чтобы кодовая база была простой для чтения - person filthy_wizard; 04.01.2019
comment
также использование rx на каждом уровне приложения - не лучшая идея. Я пытаюсь реагировать только на события backend или cache. - person filthy_wizard; 04.01.2019
comment
+ В X раз сложнее понять существующий код (даже написанный самостоятельно). + В X раз больше времени, затрачиваемого на отладку (например, без отслеживания стека, можно забыть о том, как не понимать, как работает существующее приложение, анализируя их). Согласованность транзакций, хм ... С точки зрения бизнеса + в X раз дороже, потому что требует намного больше времени на разработку / сопровождение. Мне интересно, есть ли где-нибудь сравнение рентабельности инвестиций от реактивного программирования. Я имею в виду гораздо больше денег на дорогих разработчиков, в то же время сэкономив на относительно дешевом железе :) - person Lukasz Frankowski; 07.02.2020

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

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

Вы можете увидеть несколько практических примеров реактивного программирования здесь: https://github.com/politrons/reactive

А насчет обратного давления здесь: https://github.com/politrons/Akka/blob/master/src/main/scala/stream/BackPressure.scala

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

person paul    schedule 06.02.2017

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

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

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

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

Из
https://blog.redelastic.com/what-is-reactive-programming-bc9fa7f4a7fc https://spring.io/blog/2016/06/07/notes-on-reactive-programming-part-i-the-reactive-landscape https://spring.io/blog/2016/07/28/reactive-programming-with-spring-5-0-m1

person kafkas    schedule 23.10.2017

Преимущества

  1. Более чистый код, более лаконичный
  2. Легче читать (как только вы освоитесь)
  3. Легче масштабировать (выполнять любую операцию)
  4. Лучшая обработка ошибок
  5. Вдохновленный событиями -> хорошо работает с потоками (Kafka, RabbitMQ и т. Д.)
  6. Противодавление (клиент может контролировать поток)

Недостатки

  1. В некоторых случаях может потребоваться более интенсивная память
  2. Несколько крутая кривая обучения
person EigenFool    schedule 06.07.2019
comment
Более чистый код и его легче читать, это спорно. Это не чище и не легче читать, чем использование Java Util Streams. Обработка ошибок IMHO не лучше традиционной try-catch-finally, которую тоже легче читать. - person Younes EO; 11.03.2021

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

Единственное преимущество реактивного программирования перед многопоточным - меньшее потребление памяти (каждый поток требует 0,5 ... 1 мегабайта). Недостаток - менее простое программирование.

ОБНОВЛЕНИЕ (август 2020 г.). Параллельное программирование может быть двух видов: многопоточное программирование, где основным действием является поток, и асинхронное программирование, где основным видом деятельности является асинхронная процедура (включая акторов, которые являются повторяемыми асинхронными процедурами). В многопоточном программировании используются различные средства связи: неограниченные очереди, ограниченные (блокирующие) очереди, двоичные и счетные семафоры, countdownLatches и так далее. Кроме того. всегда есть возможность создать свое собственное средство общения. В асинхронном программировании до недавнего времени использовались только 2 вида коммуникаторов: future для неповторяющихся асинхронных процедур и неограниченная очередь для акторов. Неограниченная очередь вызывает проблемы, когда производитель работает быстрее потребителя. Чтобы справиться с этой проблемой, был изобретен новый протокол связи: реактивный поток, который представляет собой комбинацию неограниченной очереди и подсчитывающего (асинхронного) семафора, чтобы сделать очередь ограниченной. Это прямой аналог очереди блокировки в многопоточном программировании. А программирование с реактивными потоками гордо называлось реактивным программированием (представьте, если бы в многопоточном программировании программирование с блокировкой очередей называлось блокирующим программированием). Но опять же, асинхронному программисту не было предоставлено никаких средств для создания собственных средств коммуникации. А асинхронный семафор нельзя использовать сам по себе, только как часть реактивного потока. При этом теория асинхронного программирования, включая теорию реактивного программирования, сильно отстает от теории многопоточного программирования.

Замечательным дополнением к реактивным потокам являются функции отображения / фильтрации, позволяющие писать линейные конвейеры, например

 publisher
     .map(()->mappingFunction)
     .filter(()->filterFunction)
     .flatmap(...)

и т.д. Но это не исключительная особенность реактивного программирования. А это позволяет создавать только линейные конвейеры, в то время как в многопоточном программировании легко создавать вычислительные графы произвольной топологии.

 

person Alexei Kaigorodov    schedule 02.11.2018
comment
Этот ответ совершенно неточный - person PhilT; 04.03.2020
comment
@PhilT этот ответ противоречит общепринятым представлениям, но абсолютно точен. Просто время еще не пришло. Когда-то люди думали, что Земля плоская, а Солнце вращается вокруг Земли. - person Alexei Kaigorodov; 04.03.2020
comment
Третье предложение противоречит второму. - person PhilT; 04.03.2020
comment
Последнее предложение первого абзаца не имеет смысла. Предложение о потреблении памяти - полная чушь. Потоки не занимают 0,5-1 МБ. - person PhilT; 04.03.2020
comment
Реактивное программирование является декларативным, а не императивным, и может использоваться как с декларативными, так и с императивными парадигмами программирования. Реактивное программирование может использоваться в однопоточном или многопоточном коде. - person PhilT; 04.03.2020
comment
Потоки не занимают 0,5–1 МБ - они могли бы занять и больше: man7 .org / linux / man-pages / man3 / pthread_create.3.html - person Alexei Kaigorodov; 04.03.2020
comment
Распределение стека потоков зависит от процессора и операционной системы. В диапазоне от 1 МБ до 10 МБ. Однако ЦП выделяет память только тогда, когда она нужна потоку. Подробнее см. В этом ответе: unix.stackexchange.com/a/280865/125333 - person PhilT; 04.03.2020
comment
Ограничения памяти в этом контексте довольно спорны, но их количество может быть более важным. Взгляните на пул потоков. - person PhilT; 04.03.2020
comment
@PhilT Я бы сказал, что на самом деле он предоставляет правильную информацию, указав обратное. - person Layman; 24.09.2020
comment
Я бы не сказал, что это совершенно неточный ответ. Просто, наряду с некоторой полезной информацией, в нем есть предвзятая тирада против реактивного программирования, дающего ответу чувство предвзятого мнения. - person Andrews; 29.06.2021