Pull to refresh

Comments 69

В мире реактивного программирования результат ее работы будет отличным от результата обычной программы такого же вида. Уже одно это плохо, если не сказать — безобразие, т.к. результат программы должен быть однозначным и не зависеть от реализации.

Вы взяли плохой и некорректный пример кода из какого-то сугубо частного источника, и распространили его проблемы на всё реактивное программирование?
Ну отлично, чё уж там.
Адекватный листинг будет выглядеть как-то так:
1. Х1 = 2
2. Х2 = 3
3. Пусть Х3 вычисляется по формуле Х1 + Х2
4. Напечатать Х1, Х2, Х3
5. Х1 = 4
6. Напечатать Х1, Х2, Х3

Надеюсь, вам очевидно, чем этот листинг будет отличаться от того, где X3 объявляется так же, как и X1 и X2. Это же и относится к вашим дальнейшим аргументам в этой части статьи: нет, в РП объявления реактивно вычисляемых значений никогда не выглядят точно так же, как и объявления переменных.
Идея понятна. Но тогда, поскольку и присваивание и Напечатать — процессы, то логично было написать:
1. Пусть X1 вычисляется (присваивается).
2. Пусть X2 вычисляется (присваивается).
3. Пусть X3 вычисляется…
4. Пусть Напечатать X1, X2, X3.
Ну, как-то так. Но сразу — вопросы. Все «Пусть...» изначально параллельны друг другу, но тогда, что можно сказать об их совместной работе? Например, в упомянутой мной книге [1] для упорядочивания параллельных операторов предлагаются A-схемы программ. Но сразу скажу и это не выход.
Основной посыл статьи — семантика языка программирования, да и его синтаксис, не должны допускать толкований и каких-то скрытых смыслов, эффектов и т.п. Поскольку все учесть сложно, должна быть теория проверяющая и выявляющая проблемы. Автоматы, их теория подобные вопросы (что я, надеюсь, хотя бы в первом приближении показал) закрывают.
В РП, по идее, тоже должно быть что-подобное — модель, теория… Приведу пример. МАТЛАБ выявляет в процессе компиляции опасные (и не только для него) обратные связи между параллельными процессами, а в РП как с этим?..
Например, Ваше уточнение все еще оставляет вопросы. И немало вопросов. Программа в конечном счете не картинка, чтобы ею любоваться и комментировать. Она должна давать ответы на все вопросы по ее функционированию.Интересно, на Boing 737 (?) не использовали ли РП?
семантика языка программирования, да и его синтаксис, не должны допускать толкований и каких-то скрытых смыслов, эффектов

Ну так в РП скрытых смыслов и нет.


Приведу пример. МАТЛАБ выявляет в процессе компиляции опасные (и не только для него) обратные связи между параллельными процессами, а в РП как с этим?..

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

… на большинстве языков программирования проверять связи просто нечем.

Но главный посыл стать — это нужно делать. Не все, что видно, всегда очевидно. Кратко и ясность, безусловно, важная вещь. Но параллелизм — коварная штука. Он за счет связей создает новый алгоритм. Меняем связи (не меняя компонент) и все — результат другой. Модель должна, если есть хоть малейшее сомнение, позволять это делать. Я это показал на примере построения результирующего автомата. Он снимает все вопросы. Есть ли подобная математика в РП. Я, если честно, в этом сомневаюсь. Человек — это, конечно, звучит гордо. Но он, к сожалению, склонен к ошибкам. Поэтому то, что он
сможет проверить сам
нужно иногда перепроверять. А для этого нужен «калькулятор». Пусть даже «на пальцах» (как в статье).

Ваш "результирующий автомат" ничего не упрощает и не проверяет, он лишь усложняет понимание.

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

Вот только доказательства строятся не так. Доказательства — это леммы и теоремы, посылки и следствия.


Мне не нужно видеть все возможные состояния программы чтобы делать выводы.

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

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

методом внимательного взгляда
Это ничто не доказывает. Как доказать, что три раза по два равно два раза по три. Применив к ним операцию умножения. Операции композиции и декомпозиции — аналоги обычных операций умножения и деления. Т.е. программы можно и умножать и делить. Вот так.

Тогда почему вы композицией и декомпозицией не пользуетесь?

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

Вот только композиция — это то, что было до умножения. Перемножив автоматы, вы от композиции избавились.

Вот если бы Вы читали мои статьи, то в предыдущей — «Модель параллельных вычислений» есть ссылка на другую — Дизъюнктивная форма структурных автоматов. В ней по поводу операций над автоматами все расписано. Там же есть и ссылка на монографию Мелихова А.Н. У меня все-таки, как я теперь понимаю, ошибочка. Я назвал операцию умножением. Неверно — надо композицией. Умножение и композиция, по Мелихову, несколько разные операции. Умножение — проще. Ее используют, чтобы вычислить композицию. В любом случае это нюансы.
Цитирую Баранова С.И. Синтез микропрограммных автоматов (и его и Мелихова можно найти в Инете): «Под задачей композиции автоматов понимается задача нахождения для сети N ее результирующего автомата S».
Так что по названию операции — не ко мне вопрос. Это так принято в теории автоматов. Вы можете, конечно, не соглашаться. И это есть Ваше право. Но я стараюсь меньше выдумывать, а пользоваться устоявшимися терминами. Если уж сопрограммы, то сопрограммы. Корутины — как-то уже режет слух.
Так и с композицией автоматов. У меня она, правда, несколько отличается, но это уже мелочи. С точки зрения нахождения результирующего автомата я использую все же операцию композиции. Вы вполне можете ввести свою операцию и назвать ее как-то иначе.

Вообще-то, я их читал.


Но я стараюсь меньше выдумывать, а пользоваться устоявшимися терминами.

Но вы только что выдумали своё понимание композиции.

Но вы только что выдумали своё понимание композиции

Конечно. Так у меня и автомат немного отличается. Тем не менее, по смыслу это и есть операция композиции.
А мою статью Вы читали? Там все расписано в деталях. И какой автомат/автоматы и какая операция композиции.

Вот только программистов не интересует ваша композиция. У нас своя есть, которая призвана упрощать программы, а не усложнять их.

Чтобы говорить от лица всех программистов для этого нужны веские основания. Я так думаю! ;)

А если Вы читали упомянутые мной книги, то, возможно, не очень их поняли. За раз, за два — это и невозможно. Иначе бы понимали, что композиция — не для «упрощения», а для, скажем так, понимания. Она ничего не упрощает, она строит фактически последовательную модель, которая эквивалентна некой сети и описывает однозначно ее поведение. Только одним «пониманием» работу сети, как и параллельной программы, т.е. ее алгоритм, нельзя описать/представить в деталях.

И мне бы хотелось знать операцию «программистской композиции», которая позволяет упрощать программы. Если можно, — где она описана? Я бы тоже не хотел бы усложнять свои программы. Я тогда бы даже поросился в сообщество, которое имеет «свою» такую эксклюзивную операцию.
Только одним «пониманием» работу сети, как и параллельной программы, т.е. ее алгоритм, нельзя описать/представить в деталях.

А его и не нужно представлять в деталях. Какой в этом смысл?


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


Если можно, — где она описана?

Библиографическую ссылку не приведу, потому что изучал программирование я не по научным трудам.


Композиция — это сборка программы из составных частей. При которой получается программа, состоящая из составных частей, а не каша из состояний.

Каша потому что не усвоили теорию автоматов. Или, если точнее, то сетей автоматов.

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

О, обратил внимание на вот этот абзац.


Итак. Построение результирующего автомата выявило явные проблемы в созданной параллельной модели. Проявятся ли они в реактивной программе — вопрос.

Нет, не проявятся. Эти проблемы присущи только построенной вами модели, но не исходной программе.

О, обратил внимание на вот этот абзац

Если бы внимательнее читали, то нашли бы еще много чего интересного ;)
Нет, не проявятся...

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

Я прочёл уйму книг,
И набит мой чердак —
То ли мудрый старик,
То ли старый м*дак.
Ну, нет ее формальной модели, которую можно было бы исследовать и что-то доказать

А куда она делась-то? У любого языка программирования есть спецификация. У любой хорошей библиотеки тоже есть спецификация. Вместе они и образуют формальную модель.


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

У вас листинг 1 и рисунок 1 расходятся.
Почему-то на рисунке на вход блока печати приезжают не выходы тривиальных блоков X1 и X2, а значения x1 и x2 (по-видимому, равные 2 и 3).


Почему блок печати посылает сигнал сброса только блоку суммирования?


Почему на рисунке 2 с автоматом состояния блоков сбрасываются после первого же использования?
А если там будет два блока печати, они что, подерутся и посбрасывают входные данные друг другу? Кстати! В листинге два блока печати, а на картинках только один. Куда они делись?


Где там защёлки, а где очереди?


В листинге 1 после второго присваивания X1=4 все старые значения уже сброшены, и надо ждать второе присваивание X2?


Ну и так далее, куча несуразностей.


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


Итого, кажется, вы и сами запутались, и других тут пытаетесь запутать.


Ах да, последний штрих к общей картине. Тэги "C++" и "Qt" каким боком?

У вас листинг 1 и рисунок 1 расходятся.
Почему-то на рисунке на вход блока печати приезжают не выходы тривиальных блоков X1 и X2, а значения x1 и x2

И это правильно, так как блок печати (см. схему) должен печатать текущие значения переменных — x1, x2. Правда, затем в исправленном варианте я предложил печатать сохраненные новые значения. А выходы блоков X1 и X2 — это их текущие состояния, которые необходимы для синхронизации с блоком X3. Своими состояниями s1 они сообщают, что произошло изменение данных (замечу, в любой их комбинации — как по одному, так и одновременно) и их можно суммировать.

(по-видимому, равные 2 и 3).


Это неизвестно. Моя программа (см. листинги) рассчитана на печать любых изменений на ее входах — x1, x2. Это так работает автомат, как активный процесс. Т.е. установка значений данных возложена на внешний процесс. Например, это может быть обычный диалог.

Почему блок печати посылает сигнал сброса только блоку суммирования?


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

Почему на рисунке 2 с автоматом состояния блоков сбрасываются после первого же использования?

Если я правильно понял Ваш вопрос, то… чтобы опять перейти к вводу данных. И замечу, что они не сразу сбрасываются, а их сбрасывает блок X3 после того, как произвел суммирование. Это существенно. И, конечно, на схеме блоку X3 надо было бы еще подвести и добавить два входа для переменных x1, x2. В коде (листинг 3) все это есть.

А если там будет два блока печати, они что, подерутся и посбрасывают входные данные друг другу? Кстати! В листинге два блока печати, а на картинках только один. Куда они делись?

А зачем два? Изменение данных разнесено во времени и потому достаточно одного. А вот в РП-программе, чтобы указать, что нужно напечатать данные, необходимо это явно указывать. По крайней мере это так в ней прописано и я так это понял. Хотя поначалу это сбивало.
Ну а если надо будет два блока печати, то — без проблем. Входы размножим. Но, правда, будут проблемы с синхронизацией с блоком X3. Но это уже надо обговаривать отдельно.

Где там защёлки, а где очереди?


Про защелки не знаю. У меня, похоже, «щелкают» блоки X1, X2, фиксируя новые значения. Очередей не предполагается. Считается, что все изменения «ловятся». У меня автоматы работают в дискретном времени от 0.1 мсек. Но можно добавить, конечно и очереди, то тогда просто усложнятся только блоки X1 и X2, имитируя выдачу данных уже из своей очереди…

В листинге 1 после второго присваивания X1=4 все старые значения уже сброшены, и надо ждать второе присваивание X2?

В том то и дело. Я не знаю как будет дальше работать программа на листинге 1. Автоматы же будут работать (вводить данные, суммировать, печатать) и ни кого и ничего не будут ждать пока их не удалят.

Ну и так далее, куча несуразностей.


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

Если вы изобретаете новый текстовый, графический и понятийный языки, то вы не имеете права говорить «нууу это и так очевидно и всем понятно».

Я не ввожу новый язык. Я использую известную модель, которую должен знать каждый. Если Вам не давали автоматы, то это больше Ваша проблема и упущение Ваших преподов. Мне кажется, что теорию автоматов (хотя бы ее начала) дают всем IT-шникам. Прочитайте мои предыдущие статьи. Там нюансы расписаны. Эта статья — их продолжение, а не так — с бухты-барахты ;).

Итого, кажется, вы и сами запутались, и других тут пытаетесь запутать.

Вы просто не очень внимательно прочли. Очень надеюсь, что тот кто внимательно читает не запутается. Как и я :).
Ах да, последний штрих к общей картине. Тэги «C++» и «Qt» каким боком?


Не понял претензий. С++ — т.к. предлагаемые автоматы — это фактически расширение С++. Ну, а Qt — так на ее базе и создано. Или что-то не так?

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


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

Не хочу спорить.

Ну, вот. Накидали «какашек» и… в кусты.
У вас своё уникальное представление о реактивном программировании, продолжайте его внедрять.

Вы не въехали. Я, если и имею, то достаточно общее представление о РП. И я не занимаюсь его внедрением. Я занимаюсь автоматным программированием. И моя статья о реализации возможностей РП (конечно, в рамках моего понимания) средствами АП. И даже не возможностей РП, а в сравнении реализации простой задачи, решенной в рамках РП и АП. Даже больше. Я постарался показать не просто реализацию, а технологию проектирования, где код — это совсем не главное. В РП, как представляется, все начинается и кончается кодом. Могу, конечно, ошибаться, но прочитанное на тему РП к такому выводу подталкивает.
Может быть, даже единомышленников найдёте.

Их и искать не надо. Те, кто использует Stateflow в MATLAB, — напрямую и есть они. Более того, подобное визуальное программирование будет определять будущее массового программирования.
Как человек, наигравшийся в своё время с этими делами, — и даже однажды засунувший сеть Петри в промышленный компьютер, — скажу, что вас ждут увлекательные приключения.

Я все «приключения» давно уже прошел ;) А потому не «играюсь», а реально использую АП в работе. С Петри, понимая сразу их проблемы, даже играться не стал :)
Как по объяснению публике, зачем вы переосмысляете термины, так и по чисто техническим вопросам.
И опять Вы — не попали. Я категорически против переосмысления. Именно потому критикую «единомышленников» типа UML, SWITCH-технологии и даже MATLAB (об этом еще будет разговор). Поэтому я, как раз, не переосмысляю, а, наоборот, пытаюсь такой тенденции что-то противопоставить. Например, чтобы не «переосмысляли» понятия теории автоматов. По ходу я объясняю, как при этом решаются технические вопросы, т.е. как я их уже решил.
У меня автоматы работают в дискретном времени от 0.1 мсек.

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

Дискретное время — это часть определения модели КА. Программы РП также работают в дискретном времени. Просто оно используется неявно. И Вы правильно поняли. Ключевое отличие модели КА от множества других вычислительных моделей — явное оперирование дискретным временем. Или, более общо, КА — полноценная кибернетическая модель дискретных систем. Остальные модели, которые об этом умалчивают, вводят народ в заблуждение. Как бы там ни было, любые программы — это прежде всего «жильцы мира с дискретным временем».

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


А во-вторых, если РП делает некоторое действие по возможности, а вы — через 0,1 мсек — то ваша модель не является корректной, и никакие рассуждения вида "а на самом деле" этого не изменят. Желаете моделировать в дискретном времени — пожалуйста, но не забудьте добавить в схему служебные сигналы для синхронизации.

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

Не в даваясь в тонкости теории… С точки зрения Кибернетики (дискретной, конечно) все просто: любой процессор — это дискретный преобразователь информации, работающий в дискретном же времени. Есть, конечно, аналоговые ЭВМ (АВМ), но это уже непрерывная Кибернетика. Надеюсь, Вы РП-программы исполняете не на АВМ? Т.е., если это не аналоговый процессор, то у остальных процессоров просто в обязательном порядке имеется тактовый генератор (об этом говорит и его характеристика — частота процессора). Так что с этим во всех смыслах все так и есть. Мир настойчиво движется к повальной дискретизации. Еще где-то остались аналоговые телевизоры (АВМ), но уже «указом» и они стали дискретными — цифровое телевидение этому способствует.
Желаете моделировать в дискретном времени — пожалуйста, но не забудьте добавить в схему служебные сигналы для синхронизации.

Я, как и Вы, не моделирую — работаю в дискретном времени. Только АП может управлять, РП — нет (всякие там таймеры, прерывания, события — не меняют картинки). Если я говорю, что работаю «через 0.1 мсек», то я гарантированно за это время реагирую на любое возникающее событие и, соотвественно, возможную реакцию на него. Чем быстрее процессор, тем меньше будет и это время. Ядро на С++, сделаю его на ассемблере — будет еще на порядок быстрее. Перенесу ядро в железо — добавлю еще минимум порядок и т.д. Будь автоматные процессоры, то они бы на два порядка были бы быстрее. Вот перспектива не только АП, но и архитектуры процессоров (замахнулись на святое — архитектуру ;)).

А сколько времени пройдет после возникновения события и реакции на него в РП-программе? Есть такие данные? Только не утверждайте, что сразу же. Мгновенного в природе нет, не было и не будет. В телепортацию не верю ;) Есть время реакции системы и еще время на обработку и выполнение действия…

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


А сколько времени пройдет после возникновения события и реакции на него в РП-программе?

Сколько — это измерять надо, но скорее всего быстрее чем у вас.


Просто потому что программа, которая что-то делает, всегда будет работать быстрее чем программа, которая сначала ждет 0,1 мсек, а потом делает то же самое.

Нет, вы за это время не гарантированно реагируете на событие, а только начинаете реагировать. У вас же обработка события в общем случае не за 1 переход происходит?
Представим отсечки тактов на временной оси. Если событие случается до отсечки, то оно гарантированно ловится и может быть обработано даже за один такт. Здесь, естественно, надо различать время реакции и время обработки. Если событие случится внутри такта, то оно может быть пропущено (а, может, и нет), но на следующем такте оно будет гарантированно обработано. Т.е. время реакции на событие гарантированно <= 0.1 мсек. Обработка — отдельный вопрос. Все зависит от автомата. Безусловно это может быть и больше одного такта. Но самый удачный случай, когда все делается в пределах 0.1 мсек. Худший — 0.2 мсек с учетом и обработки события в пределах такта…

Т.е. среда АП дает определенную и известную заранее гарантию. Поскольку есть дискретное время работы процесса и возможность управления им. В РП, похоже, «измерять надо». А если еще много процессов? И, вообще, управление дискретным временем интересная и полезная вещь.

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

Повторюсь, РП работает заведомо быстрее этой гарантии в большинстве случаев. Меньшинство случаев — это микроконтроллеры и геймдев.


А если еще много процессов?

То РП справится с ними лучше чем автоматы.


Потому что РП тратит время только на активные процессы, а ваши автоматы тратят его в холостую.

Потому что РП тратит время только на активные процессы, а ваши автоматы тратят его в холостую.
Процессы, управляемые событиями, — это не активные процессы.
Но, замечу, активностью автоматных процессов можно легко управлять. Как — показано в моей предыдущей статье Автоматы — вещь событийная?
Напомню. Возьмем тот же калькулятор из статьи. С одной стороны, ему можно увеличить дискретное время. И это уменьшит системные потери на реализацию параллельных процессов. С другой стороны, — перевести автомат в пошаговый режим, запуская его затем событиями. Именно это реализовано в упомянутой статье.
Так что с автоматами не все так грустно. ;)
С одной стороны, ему можно увеличить дискретное время. И это уменьшит системные потери на реализацию параллельных процессов.

Мёртвому припарки. Вам придётся постоянно подгонять эту настройку под конкретную систему и конкретную программу.


С другой стороны, — перевести автомат в пошаговый режим, запуская его затем событиями.

Это единственный нормальный сценарий использования автоматов. Только я немного не понимаю, о каких "гарантированных 0.1 мсек" в таком случае будет идти речь?

Это единственный нормальный сценарий использования автоматов. Только я немного не понимаю, о каких «гарантированных 0.1 мсек» в таком случае будет идти речь?
Наука должна стараться давать ответы на все вопросы. Или хотя бы на задаваемые.
Кибернетика рассматривает два нормальных сценария использования автоматов — синхронный и асинхронный их режим работы.В синхронном режиме автомат имеет дискретные такты строго одинаковой длительности. В асинхронном режиме длительность такта «плавающая». В последнем случае это может быть, как максимальная скорость работы автомата, так и скорость задаваемая внешней средой. В нашем случае событиями.
Соответственно среда исполнения автоматов должна их оба и реализовывать. Так, на уровне конфигурирования приложения я могу автомату задать асинхронный режим работы (работа с максимальной возможной скоростью) или синхронный — работа с заданным (гарантированным) дискретным временем. А на программном уровне управлять дискретным временем, включая привязку к событиям (как в статье)
Кибернетика рассматривает два нормальных сценария использования автоматов — синхронный и асинхронный их режим работы.

Но в этой статье вы рассматриваете не всю кибернетику, а конкретную программу, написанную в реактивной парадигме.

О, вот ещё интересный момент:


Например, в чем отличие реактивного программирования (РП) от событийного или потокового?

Не уверен, что подобные вопросы уместны на Хабре в формате поста (уместнее было бы узнать ответ на этот вопрос до написания статьи), но всё же отвечу.


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


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


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


Что такое потоковое программирование в вашем понимании — я не знаю (у меня есть три разные догадки), но если вы расскажете про потоковое программирование точнее — расскажу вам про разницу с РП.

но если вы расскажете про потоковое программирование точнее

Цитирую (ссылка на книгу в статье «Элементы...»): При потоковом управлении действие (оператор или операция) программы может выполнится, если готовы все необходимые для него аргументы (операнды)…
Если в событийном управлении условия готовности привязаны к управляющим событиям, то в потоком управлении они изменяются исключительно под влиянием потоков данных, которыми обмениваются операторы (или операции).

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

Что значит двунаправленность?
Ещё для РП характерно внимательное отношение к количеству слушателей каждого события, влияющее на логику источника: источник событий может прекратить свою работу если у него не осталось подписчиков, или приостановить свою работу если все его подписчики заняты.
Рассматривается ли каждое изменение данных, как событие? Например, изменение X1, X2 да и затем X3 — будут ли это события? Или это необходимо как-то указать, т.е. связать переменную с неким событием.
Еще. В листинге 1 рассматривается операция суммирования. Как понять работает ли она с событиями или с обычными переменными?
Цитата (про потоковое): «Условие готовности в этом случае носит стандартный характер и не прописывается явно в программе...»
Такое впечатление, что листинг 1 также использует некие умолчания, реагируя возможно на события. Например, похоже, так поступает второй оператор Напечатать. Да и суммирование опять же выполняется, хотя и изменена только одна переменная. Так ли это?
Еще вопрос ;) Если оператор/функция работает с несколькими событиями, то реагирует она ровно на это множество событий (как потоковая функция) или хотя бы на любое одно и/или несколько из них?

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


Такое впечатление, что листинг 1 также использует некие умолчания

Совершенно верно. Тот пост, откуда вы его взяли, как раз и пытался рассказать про эти самые умолчания.


Еще вопрос ;) Если оператор/функция работает с несколькими событиями, то реагирует она ровно на это множество событий (как потоковая функция) или хотя бы на любое одно и/или несколько из них?

От оператора зависит. Их много, они разные.


Да, важное уточнение: операторы работают не с событиями, они работают с реактивными объектами — потоками событий (в РП "на потоках") или переменными (в РП "на обзёрваблах", точного термина не знаю).

Вы не против, если я продолжу забрасывать Вас вопросами? ;)

Таким образом в РП переменные представлены двумя классами — обычными и реактивными. И, наверное, в их объявлении это как-то учитывается. Так?
Попробую «проложить» аналогию. В АП (автоматном программировании) выделяются обычные переменные и переменные теневой памяти. Последние — это объекты типа CVar, которые, как и обычные, могут быт int, bool и т.д.

О процессах. В АП каждый процесс — автомат. Много процессов — сеть автоматов. Каждый автомат — активный процесс, т.е. процесс, который «крутится» постоянно (в дискретном времени, конечно). В процессе этого «крутежа» от работает с обычными данными и данными в теневой памяти. С чем и как работать — это уже его дело.
Как в РП? Я могу предположить, что кажый оператор РП представляет процесс. Ну, как в листинге 1 это оператор суммирования и оператор Напечатать. Т.е. эти два оператора, как два параллельных процесса. Теперь — ближе к делу. Каждый оператор/функция РП — это активный процесс, или процесс, который работает лишь тогда, когда возникают события? Или, скажем так, есть активные и пассивные операторы? Как их тогда отличить? А как будет работать оператор, который работает только с обычными (не реактивными) переменными? Видимо, можно считать, что и операторы РП работают в дискретном времени (мы запускаем программы на обычных компах, а не на аналоговых)?

Нет, в РП операторы не работают в дискретном времени, они работают строго по событиям. "Активных" в вашем понимании операторов не существует.


Ну, как в листинге 1 это оператор суммирования и оператор Напечатать.

Нет, в листинге 1 используется только 1 оператор — оператор комбинирования; в библиотеках группы ReactiveX он называется CombineLatest, в mobx он называется computed. Операция сложения тут — лишь один из параметров оператора комбинирования.


"Напечатать" в том листинге — вообще не оператор, а простая конструкция внешнего для РП языка. Реактивный оператор был бы написан в листинге как-то так:


4. При каждом изменении Х3 напечатать текущие значения X1, X2, X3

В ReactiveX такой оператор называется Subscribe, в mobx — autorun или reaction.

Нет, в РП операторы не работают в дискретном времени, они работают строго по событиям. «Активных» в вашем понимании операторов не существует.

Реальный мир, кроме откровенных «кирпичей», активен по своей сути. Любой объект, реализующий тот или иной алгоритм, по определению также функционирует в дискретном времени. Операторы, даже если не активны, просыпаясь время от времени, все же реализуют в эти моменты некие алгоритмы, а потому и живут и работают в дискретном времени.
Для тех, кто ставит «минусы». Вольно или нет, но на них обращаешь внимание. И задаешься вопросом — за что? Как в данном случае. Что я в этом случае сказал «отрицательного»? Но как это узнать? Я бы предложил подобное анонимное и «плюсование» и «минусование» сопровождать обязательным комментированием. Пусть оно будет приватным. А иначе любой «накруткой» можно заниматься, не особенно вникая в смысл комментария и без последствий.

Возвращаемся к сути сказанного. Я напомнил бы о давно известном — о началах дискретной кибернетики. Их еще не опровергли, кстати. Поэтому, как говорится, изучайте «матчасть». В дискретной кибернетике любой прибор/объект, преобразующий информацию, рассматривается как дискретный преобразователь, работающий в дискретном времени. Если кто-то это отрицает, то ему надо просто перечитать, например, Введение в кибернетику Глушкова В.М. Это относится в первую очередь к «минусовщикам». И если объект «пинают» событиями, это не отменяет «дискретных начал» кибернетики. Просто в этом случае можно считать, что моменты возникновения событий совпадают с отметками дискретного времени на оси времени.

«Минусовщикам» — читайте, пожалуйста, умные книжки. Занимайтесь самообразованием, если что-то упустили ранее или вам этого не дали. И тогда ваши мысли примут правильное направление. Надежда, может быть слабая, но хочется все же надеяться на лучшее ;)
В дискретной кибернетике любой прибор/объект, преобразующий информацию, рассматривается как дискретный преобразователь, работающий в дискретном времени

"Рассматривается" — это не то же самое, что "является".


И если объект «пинают» событиями, это не отменяет «дискретных начал» кибернетики. Просто в этом случае можно считать, что моменты возникновения событий совпадают с отметками дискретного времени на оси времени.

Но это не делает "работу по событиям" и "работу в дискретном времени" синонимами.

«Рассматривается» — это не то же самое, что «является».
Безусловно. Есть модель и есть реальный объект. Только нужно учитывать, что есть модели программ и реализации этих моделей. Как правило, программы и есть реализации тех или иных вычислительных моделей. Исключений в этом плане нет. Так что в нашем случае и «рассматривается» и «является» и будут фактически синонимами. Или, что точнее, РП-программы — реализация РП-модели. Автоматные программы — реализация автоматной модели. Уже доказано, что автоматные программы (машина Тьюринга) реализуют любую другую модель. Про РП-модель — мне не известно.
Но это не делает «работу по событиям» и «работу в дискретном времени» синонимами.
Я показал, как в рамках теории автоматов поставить между ними, как раз, знак равенства. Ваше утверждение не является опровержением.

У любой модели есть область применимости. Хорошо что вы упомянули машину Тьюринга — потому что её никогда не используют при оценке сложности вычислений, выходящей за рамки "полиномиальная/неполиномиальная". Просто потому что эмуляция реальных компьютеров на машине Тьюринга добавляет к оценке несколько лишних множителей.


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

Если бы вы правда читали все те книги, на которые ссылаетесь — вы бы это понимали
Даже не буду спорить;)
Однако, хотелось бы вернуть Вас в тему разговора… Если РП-программа функционирует от одного события к другому, то можно ли каждому такому событию сопоставить некое «внутреннее состояние» РП-программы?

В однопоточном случае — да. В многопоточном — нет (тут ломают модель особенности современных многоядерных процессоров).


Лучше рассматривайте не программу целиком, а отдельные реактивные объекты — у них всегда есть определённое состояние.

А в чем принципиальное отличие однопоточной РП-программы от многопоточной?
Лучше рассматривайте...
Давайте пока будем рассматривать, как я предложил — состояния [любой] РП-программы в моменты совершения событий. С однопоточным случаем вроде бы все понятно. Давайте добьем многопоточный.
Пока не ясны их отличия. Хотя, если честно, в моем скромном понимании этого (отличия) быть не должно. Хотя бы исходя из тех соображений, что правильную модель ничто «поломать» не может.

А с чего вы взяли, что ваша модель — правильная?


PS Я забыл вчера уточнить, что хоть состояние и существует — но общее количество возможных состояний бесконечно.

Я про свою модель — пока ни слова, ни буковки ;)
PS Я забыл вчера уточнить, что хоть состояние и существует — но общее количество возможных состояний бесконечно.

Хотя Вы и не ответили на мой прямой вопрос — вернемся на шаг назад — к уточнению.
Что Вы понимаете тогда под состоянием РП-программы?
Почему их число бесконечно?
Я про свою модель — пока ни слова, ни буковки ;)

Хорошо. С чего вы взяли, что не ваша модель — правильная?


Почему их число бесконечно?

Потому что число порождаемых в ходе выполнения программы реактивных объектов неограниченно. А у каждого есть своё состояние.

Пока я взял за аксиому, что РП-модель и есть правильная модель…
А у каждого есть своё состояние.
Все же первым был вопрос — что понимается под состоянием РП-программы на момент временной отсечки, представленной событием? Без понимания этого сложно двигаться дальше.

Что-то, что кодирует состояние каждого реактивного объекта, из которых она состоит. Если бы число этих самых объектов не менялось во время работы программы — то состояние РП было бы кортежом, составленным из состояний базовых объектов.


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

В соответствии с теорией автоматов любому коду ставится в соответствие некий символ. Т.е. любое состояние РП-программы может быть сведено к «имени» этого состояния (в Вашем смысле). Все эти символы — множество состояний РП-программы. Это множество может быть конечным и бесконечным — проблем нет. На самом деле программ с бесконечным множеством состояний, если их не понимать как-то своеобразно, фактически нет. Их может быть, ну, очень много. Но бесконечно — нет. Вы не кодируете Вселенную, а работаете в достаточно ограниченном пространстве. В теории машин Тьюринга (да и аналогичной) сказали бы — с конечной лентой. Только не надо, искусственно увеличивая число состояний, включать в него и состояние ленты. А часто поступают именно так. Это не верно. Состояния любой программы нужно понимать в смысле состояний МТ. Тогда их будет много-много меньше, чем «бесконечность».

Итак. Если у РП-программы есть состояния (Вы с этим согласились), то любой РП-программе соответствует эквивалентный один автомат с этим же множеством состояний. Это будет или конечный автомат или пусть даже бесконечный. Но и то и другое — есть асинхронная автоматная модель РП-программы. Вот и все доказательство. Только не надейтесь, что, создавая автоматный эквивалент РП-программы, я буду строить именно такой автомат :)

Ну есть он (в однопоточном варианте), с этим я не спорил. Что из этого следует-то? И зачем так долго доказывать очевидные вещи?

И зачем так долго доказывать очевидные вещи?
Приходится, чтобы они стали очевидными.
Продолжим. Существует взгляд на работу любого объекта/программы с позиций так называемого «черного ящика» (ЧЯ), где понятны его входы и его выходы (результаты работы). Так вот с позиций ЧЯ работа многопоточной реализации программы неотличима от однопоточной реализации. Следовательно, для любой многопоточной программы существует эквивалентная — однопоточная. Таким образом, теперь уж любая РП-программа, а не только однопоточная, реализуется, как минимум, одним конечным автоматом. Или это тоже очевидное доказательство?
Что из этого следует-то?
Многое. Зачем вводить новый вид программной РП-модели, не имеющей теории, если есть автоматное программирование, базирующееся на проверенной теории и технологии проектирования.
Конечно, можно «назло бабушке...». Уже одно то, что РП-программа, как Вы утверждаете, имеет «бесконечное число состояний», а множество состояний автоматной программы для РП-программиста — каша, вызывает, скажем так, смешанные чувства :)
Зачем вводить новый вид программной РП-модели, не имеющей теории

Потому что наличие теории само по себе достоинством не является.


И да, перестаньте перевирать мои слова:


же одно то, что РП-программа, как Вы утверждаете, имеет «бесконечное число состояний»

Только при моделировании вашим методом "склеим всё в один автомат".


а множество состояний автоматной программы для РП-программиста — каша

Не "для РП-программиста", а для нормального человека (не робота и не учёного-теоретика). И не любое множество, а то, которое построили вы.

Цитирую Вас:
PS Я забыл вчера уточнить, что хоть состояние и существует — но общее количество возможных состояний бесконечно.

Так кто кого перевирает?
Остальное, если честно, комментировать уже просто не хочется :( Все уже было и написано и сказано…
Я бы предложил подобное анонимное и «плюсование» и «минусование» сопровождать обязательным комментированием. Пусть оно будет приватным.
И анонимным.
Sign up to leave a comment.

Articles