Re: SObjectizer: I Love This Game!
От: Alex Alexandrov США  
Дата: 17.03.06 18:55
Оценка:
Здравствуйте, Евгений Охотников, Вы писали:

ЕО>Статья:

ЕО>SObjectizer: I Love This Game!
Автор(ы): Евгений Охотников
Дата: 31.03.2006
Данная статья знакомит читателя с проектом SObjectizer -- инструментом для агентно-ориентированного программирования на C++. Раcсказывается о его истории, текущем состоянии и ближайших перспективах. Обсуждаются некоторые преимущества, которые дает SObjectizer, а также некоторые его недостатки и проблемы.


ЕО>Авторы:

ЕО> Евгений Охотников

ЕО>Аннотация:

ЕО>Данная статья знакомит читателя с проектом SObjectizer -- инструментом для агентно-ориентированного программирования на C++. Раcсказывается о его истории, текущем состоянии и ближайших перспективах. Обсуждаются некоторые преимущества, которые дает SObjectizer, а также некоторые его недостатки и проблемы.

Линк http://msk.nestor.minsk.by/kg/2000/kg0009/kg03710.html — мертвая
It's kind of fun to do the impossible (Walt Disney)
Re[2]: SObjectizer: I Love This Game!
От: eao197 Беларусь http://eao197.blogspot.com
Дата: 18.03.06 06:09
Оценка:
Здравствуйте, Alex Alexandrov, Вы писали:

AA>Линк http://msk.nestor.minsk.by/kg/2000/kg0009/kg03710.html — мертвая


Да, линк поменялся уже после выхода журнала из печати. Вот правильный (пока?) http://msk.nestor.minsk.by/kg/2000/37/kg03710.html

2rsdn team: а как можно исправлять ошибки/ссылки в уже опубликованной статье?


SObjectizer: <микро>Агентно-ориентированное программирование на C++.
Re[6]: SObjectizer: I Love This Game!
От: Alexmoon Украина  
Дата: 31.03.06 09:32
Оценка: 18 (3) :)
Здравствуйте, VladD2, Вы писали:

VD>1. Уверен, что скорость продукта в большей степени зависит от качества кода и алгоритмов. Ява даст оверхэд в среднем процентов в 20-70. Это не те цифры.

VD>2. Кто сказал, что скорости не достаточно, а надежности избыточно? Вот аноним намекает на то, что как раз недостаточно надежности.
VD>3. Перефразирую себя. Написать один сервер окуратно на С++ задача решаемая. Если потратить много денег/времени на тестирование, то он без сомнения будет работать. Но вот писать прикладной код на С++ — это маразм. На это способны еденицы. И если ты хочешь чтобы твой сервер был востребован, то его АПИ должен быть ориентирован на безопасный язык!
1. От качества кода зависит абсолютно все и в том числе гарантированная надежность. Оверхед в 20-70 процентов — это для вас лично не те цифры. Напомню еще раз у всех свои принципы отношения к подобным вещам и если исходить из принципа что софт должен быть написан быстро и как можно более дешевым программистом, то все — не те цифры, кроме возможности чтобы он вообще что либо написал.
2. Не для кого не секрет, что в нашей проф. среде есть два принципиально разных подхода — это кодирование и программирование. Вторые делают гарантированно надежные приложения на С++, а первые не сделают их никогда. Это условно. Читайте между строк, если кого то это обидело. Язык и платформа — это не цель а средство.
3.Если писать прикладухи на С++ будет человек не имеющий отношения к программированию — тогда и только тогда это маразм. Писать гарантированно надежные, не боюсь писать этого словосочетания, на С++ способны далеко не идиницы. Проблема не в языке, а в том что мы разленились совсем. С++ в этом случае как раз дает намного более удачную гибкость при разработке. Мои друзья перешедшие полностью под NET привожят лишь одно достойное утверждение и в душе они сами с этим согласны — "думать надоело." Это хоть и грубо, но мы все боимся правды как огня.
4. Если ты хочешь чтобы твой сервер был востребован, то

зависит от качества кода и алгоритмов

, а не лишь утверждение что

то его АПИ должен быть ориентирован на безопасный язык

. Последняя цитата связана с востребованностью точно так же, как заметил автор ниже Dj.ValDen:

"Вы проиграли в футбол потому, что у вас правостороннее движение."


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

Наводящий вопрос. Что значит словосочетание море кода в наше время при компонентном, библиотечном и т.д. подходе. Такие утверждения можно голословно привязать и к твоим подходам.

[skip]

E>> Существует масса кода на C/C++, которые работают в режиме 24x7, не глючат и не падают. Существует не мало кода на Java, который должен был бы работать в режиме 24x7, но падает.

VD>Ой, позволь не поверить. Думаю что работающего прикладного серверного кода написанного на Яве куда больеше чем написанного на С++.
А ты поверь. Почему можно делать надежный софт на чем угодно я написал выше, а насчет последнего приложения, позволю себе пошутить, да ровно на одну больше, но о чем это говорит? И не отвечай что о надежности. Ты сам знаешь, что это не так.

E>>Разговоры о том, что на C++ нельзя писать надежные программы -- это от лукавого.


VD>Гарантированно надежные — это факт. Ну, да я не о том. Я о общей надежности решений. Если бы твои слова были бы правдой, то веб-приложения писались бы на С++, а Ява никогда не заняла бы такой огромный рынок.

Это факт(это не подтверждение твоих слов). И так всем понятно о чем я, но писать больше смысла нет. Они не пишутся на С++ совершенно по другой причине. Лепить к недостатку С++ чистое количество — это не разговор. Интересно какого одобрения ты ожидал утверждая именно так.

E>> Очень похожи на разговоры о том, что на динамических языках нельзя писать надежные программы.


VD>Что считать динамическими? На динамически типизированных? Все завист от сложности системы. Монолитные огромные наврено сложно писать. А нечто вроде веб-приложений можно. Вот только при этом языка должен быть безопасным. Большинство динамически типизированных языко этому требованию удовлетворяют. А С++ — нет. Потому он и не пригоден для разработки прикладного серверного софта. То жест потенциально конечно и на ассемблере можно написать код без ошибок. Но чем больше объем системы, чем больше и разношерстнее команда разрботчиков, чем меньше сроки, тем меньше вероятность получения надежного продукта. Причем в отличии от типобезопасных языков не факт, что удастся за счет одного-двух талатнливых программистов быстро исправлять глуюки.

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


E>> И то и другое не верно. Скорее C++ не облегчает написание надежных программ. Поэтому первый же дятел-разработчик легко вызывает крах большой системы.

VD>Знашь, я вот сомтрю вокур и удивляюсь. С кем не заговоришь так он не дятел. А вокруг одни дятлы, дятлы, дятлы...
No comments.

1. Здесь обсуждение конкретной статьи, а не продолжние сериала StarWars. Первые пару постов я и так держал себя в руках. Мы все взрослые люди и знаем что говорим. Раз ты вызвался, то я ответил на вопрос. Я старался быть как можно более корректным.
2. Чтобы ты не подумал плохого, я тебя очень уважаю как коллегу. Ничего лишнего. Только мысли вслух. Я вернусь к обсуждению, только лишь по поводу статьи, если будет что сказать нового.
Re: SObjectizer: на SourceForge
От: eao197 Беларусь http://eao197.blogspot.com
Дата: 31.03.06 10:40
Оценка:
ЕО>Статья:
ЕО>SObjectizer: I Love This Game!
Автор(ы): Евгений Охотников
Дата: 31.03.2006
Данная статья знакомит читателя с проектом SObjectizer -- инструментом для агентно-ориентированного программирования на C++. Раcсказывается о его истории, текущем состоянии и ближайших перспективах. Обсуждаются некоторые преимущества, которые дает SObjectizer, а также некоторые его недостатки и проблемы.


ЕО>Аннотация:

ЕО>Данная статья знакомит читателя с проектом SObjectizer -- инструментом для агентно-ориентированного программирования на C++. Раcсказывается о его истории, текущем состоянии и ближайших перспективах. Обсуждаются некоторые преимущества, которые дает SObjectizer, а также некоторые его недостатки и проблемы.

Текущая бета версия последней, разрабатываемой сейчас, версии SObjectizer доступна на SourceForge под BSD лицензией.

Приглашаются все желающией посмотреть, попробовать... Может кому-то и понравиться


SObjectizer: <микро>Агентно-ориентированное программирование на C++.
Re: SObjectizer: I Love This Game!
От: Аноним  
Дата: 01.04.06 12:44
Оценка: +1
Здравствуйте, Евгений Охотников, Вы писали:

ЕО>SObjectizer является моим любимым инструментом.


Могу рассказать одну историю.
Жил-да-был один студент. Настала пора сдавать экзамен по программированию. Билет ответил, задачу решил — ждет пятерку. И тут препод спрашивает: а почему Вы при решении использовали очередь, а не стек? Студент честно отвечает: а я зачетную задачу на очередях делал, и вообще у меня очереди — любимый инструмент. Посмотрел на него преподаватель и сказал: у программиста не должно быть "любимых" инструментов, он должен использовать наиболее целесообразный инструмент для каждой решаемой задачи. И поставил студенту 4, а не 5.

ИМХО, статья описывает восторг создателя от собственной разработки. Но это еще полбеды. Найденное решение "заперло" автора в рамках одной парадигмы — как он сам признается, ему стало трудно решать те задачи, где неприменим агентный подход. Могу лишь советовать автору прочитать пару книг о паттернах и убедиться, что предлагаемое им решение — не что иное как реализация нескольких (но далеко не всех!) классических методик. Нужно отойти в сторону и взглянуть непредвзято

P.S. Добавлю, что тем студентом был я, и преподавателю тому ныне весьма благодарен.
Re[2]: SObjectizer: I Love This Game!
От: eao197 Беларусь http://eao197.blogspot.com
Дата: 01.04.06 13:04
Оценка: +2
Здравствуйте, Аноним, Вы писали:

А>ИМХО, статья описывает восторг создателя от собственной разработки. Но это еще полбеды. Найденное решение "заперло" автора в рамках одной парадигмы — как он сам признается, ему стало трудно решать те задачи, где неприменим агентный подход.


Поэтому я решаю задачи, в которых агентный подход применим. И использую для решения SObjectizer.
Разве я в статье предлагал писать на SObjectizer Web-приложения (хотя это вполне возможно)? Или расчет распределения температуры на лопастях газовой турбины? Или разработку компилятора C++ на SObjectizer делать? Что-то не припоминаю такого.

A>Могу лишь советовать автору прочитать пару книг о паттернах и убедиться, что предлагаемое им решение — не что иное как реализация нескольких (но далеко не всех!) классических методик. Нужно отойти в сторону и взглянуть непредвзято


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

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

Так что может отойдем от общих рекоментаций по поводу полезности просвящения и попробуем поговорить более предметно?


SObjectizer: <микро>Агентно-ориентированное программирование на C++.
Re: Конструктивная критика 1
От: remark Россия http://www.1024cores.net/
Дата: 01.04.06 23:17
Оценка: 12 (1) +1
Здравствуйте, Евгений Охотников, Вы писали:

ЕО>Статья:

ЕО>SObjectizer: I Love This Game!
Автор(ы): Евгений Охотников
Дата: 31.03.2006
Данная статья знакомит читателя с проектом SObjectizer -- инструментом для агентно-ориентированного программирования на C++. Раcсказывается о его истории, текущем состоянии и ближайших перспективах. Обсуждаются некоторые преимущества, которые дает SObjectizer, а также некоторые его недостатки и проблемы.


ЕО>Авторы:

ЕО> Евгений Охотников

ЕО>Аннотация:

ЕО>Данная статья знакомит читателя с проектом SObjectizer -- инструментом для агентно-ориентированного программирования на C++. Раcсказывается о его истории, текущем состоянии и ближайших перспективах. Обсуждаются некоторые преимущества, которые дает SObjectizer, а также некоторые его недостатки и проблемы.


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


1. Пугает идентификация событий и сообщений строкой:
so_subscribe( "evt_hello_time", "msg_hello_time" );


Даже, если копи-пастить эти строки, то ошибки возможны. Не говоря уже о сопровождаемости.
Ошибки могут отлавливаться только в ран-тайме, и только при запуске нужной ветви кода. Т.е. ошибка может быть в коде и быть обнаружена только через неопределённое время. В с++ и так много о чём приходится думать — неправильно записанный идентификатор сообщения — это не та проблема, о которой я хочу думать во время написания кода, и проводить время за отладкой для поиска.

Я имел дело с приложением, где запросы sql были размазаны по врему коду проекта. В нескольких таблицах имелось поле status. Плюс в программе было много разных лексемм, включающих слово status. Пока всё было протестированно и более-менее работало — нормально. Но когда встала например проблема удалить из одной таблицы поле status, то это было не легко. Приходилось искать в проекте слово status, но оно встречалось в запросах и в самом коде, причём в запросах оно могло иметь отношение у разным таблицам и быть записано в разном регистре, ну и в коде встречалось не редко...

У printf с его форматными строками проблемы растут оттуда же — есть переменная int в одном месте и форматная строка "%d" — вдругом. Потом кто-то меняет тип переменной на unsigned char — исход понятен. Или есть переменная CString и форматная строка "%s", потом кто-то меняет переменную на std::string — исход тоже понятен.

Вывод: в своём серьёзном проекте я бы не хотел видеть такие моменты — процент глупых ошибок связанных с этим при поддержке иногда доходит до 50% и больше. Самое обидное, что их мог бы отлавливать компилятор.
Что хотелось бы видеть: сообщения и события в виде типов, значений или ещё чего-то, что понимает компилятор. И чтобы при внесении изменений в одном месте компилятор сразу показывал возникшие проблемы в других местах.

Я недавно экспериментировал с наброском реализации publisher/subscriber. Там я сделал сообщения в виде типов:

struct TextChangedEvent : Event<TextChangedEvent>
{
    TextChangedEvent(const std::string& text, int id)
        : text_(text)
        , id_(id)
    {}

    std::string text_;
    int id_;
};


Тут же мы сразу привязываем данные к сообщению. А регистрацию в инфрастуктуре обеспечивает : Event<TextChangedEvent>.

Отправка:

send(TextChangedEvent(newText, myID));


Приём сообщения:

void process(const TextChangedEvent& e);


Эта же строчка обеспечивает подписку.
Всё полностью типобезопасно. Никаких cast'ов. На любые ошибки компилятор сразу ругается.
При этом удалось избежать централизации — т.е. например необходимости прописывать в базовом интерфейсе IEvent функций для обработки всех имеющихся типов сообщений.
Правда до логического завершения эту идею я так и не довёл тогда...




1024cores &mdash; all about multithreading, multicore, concurrency, parallelism, lock-free algorithms
Re: Конструктивная критика 2
От: remark Россия http://www.1024cores.net/
Дата: 01.04.06 23:18
Оценка:
Здравствуйте, Евгений Охотников, Вы писали:

В продолжение предыдущего сообщения.

2. Всю документацию полностью не прочитал, но как я понял все сообщения в системе идут через единый коммутатор. В MPI (я так понял, ты с ним знаком) есть понятие коммутаторов, т.е. сущностей, которые принимают, маршрутизируют и отправляют сообщения. Для крупной системы имело бы смысл иметь несколько коммутаторов. Как с т.з. производительности, так и с т.з. логики работы. Коммутаторы могут иметь отношение к абсолютно разным частям системы — один к ui, другой к БД, другой к бизнес-логике, другой к инфраструктуре приложения. И зачем подсистеме ui иметь возможность принимать сообщения связанные с БД непонятно.

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

Отправка должнf выглядеть как:

send(message); // Отправка на глобальный коммутатор
send(message, subsystemNcommutator); // Отправка на коммутатор подсистемы N


Подписка объектов на коммутаторы:

subscribe(subsystemNCommutator);
subscribe(applicationFrameworkCommutator);




1024cores &mdash; all about multithreading, multicore, concurrency, parallelism, lock-free algorithms
Re: Конструктивная критика 3
От: remark Россия http://www.1024cores.net/
Дата: 01.04.06 23:19
Оценка:
Здравствуйте, Евгений Охотников, Вы писали:

В продолжение предыдущего сообщения.

3. Состояния и агент являются монолитом. Агент находится сразу во всех состояниях по крайне мере в том смысле, что он должен содержать все данные, которые нужны всем его состояниям. Это плохо, т.к. (1) нелогично, (2) может привидить к ошибкам (когда агент обращается к своей переменной-члену, которая логически не имеет смысл в текущем состоянии агента, но физически она существует) и (3) может быть расточительно (данные одного состояния большие, но требуются очень редко).
Хотелось бы видеть состояния, как отдельные объекты. Например:

class Socket : public Agent<ActiveSocketState, PassiveSocketState>
{
    //...
};

class ActiveSocketState : State<ActiveSocketState>
{
public:
    void process(SocketDeactivateEvent&);
    void process(SocketPacketReceive&);

private:
    byte internalBuffer[65536];
};

class PassiveSocketState : State<PassiveSocketState>
{
public:
    void process(SocketActivateEvent&);
};


Переменная internalBuffer существует, занимает место в памяти, и доступна только в состоянии ActiveSocketState. В других состояниях к ней даже нельзя обратиться.
При небольшом извращении с языком, можно добиться, что бы такая конструкция являлась так же и описанием агента для SObjectizer, т.е. отпадает необходимость в SOL4_CLASS_START.
На данный момент при описании SOL4_CLASS_START присутствует дублирование и описание не так явно — ты писал в недостатках, что иногда забывают добавлять что-то в описание агента. При моём предложенном подходе, такие забывания сократились бы, т.к. не надо "при добавлении сюда, не забыть добавить туда".


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



1024cores &mdash; all about multithreading, multicore, concurrency, parallelism, lock-free algorithms
Re: Конструктивная критика 4
От: remark Россия http://www.1024cores.net/
Дата: 02.04.06 00:03
Оценка: 12 (1)
Здравствуйте, Евгений Охотников, Вы писали:

В продолжение предыдущего сообщения.

4. Синхронные сообщения — всё-таки они нужны. Их отсутствие сужает область применения, если не в два раза, то по крайней мере на треть.
Это всё равно как заставить у всех функций использовать возвращаемый тип только void.

Иногда надо вернуть какой-то результат. Без этого теряется весь смысл. Т.е. подписчик на сообщение должен не только сделать что-то сам, но и сообщить что-то издателю. Самые простые примеры — есть контрол с текстом, и есть подписчики-валидаторы, которые при изменении текста должны его проверить и сообщить результат. Или какое-то важное сообщение (оповещение о завершении работы приложения).

Или взять например систему сообщений Windows — там всегда предусмотрена возможность вернуть результат обработки. У вас при использовании SObjectizer просто всегда есть возможность сделать обычный статический вызов при необходимости получить результат, а что если бы её не было? Или объект, у которого вызывается метод, надо перенести на другую машину? В случае, если имеется sync_send никаких доработок не понадобиться.

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

По поводу дедлоков — тут никуда не деться, тут они всегда были и остануться.


Фактически сейчас есть возможность отправлять синхронные сообщения:

struct SyncMessageParams
{
    int result;
    Event messageProcessed; // Событие, что сообщение обработано
    void wait(); // Ждать, пока сообщение не обработается
};

SyncMessageParams params;
async_send("msg", &params);
params.wait(); // Ждём пока сообщение будет обработано
if (params.result) ...;


Тока единственная проблема — только инфрастуктура может знать, что все подписчики обработали сообщение, и установить Event messageProcessed.
Поэтому нужна хотя бы минимальная поддержка со стороны инфрастуктуры — чтобы она установила Event после того как всё подписчики обработают сообщение. Необходимость такого действия можно определять например так: если параметры сообщения отнаследованы от некого SyncParams, то значит сообщение синхронное и надо установить этот Event.

В идеале, конечно, хотелось иметь более широкую поддержку синхронности.



1024cores &mdash; all about multithreading, multicore, concurrency, parallelism, lock-free algorithms
Re[2]: Конструктивная критика 1
От: eao197 Беларусь http://eao197.blogspot.com
Дата: 02.04.06 13:13
Оценка:
Здравствуйте, remark, Вы писали:

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


Большое спасибо за проявленный интерес и потраченное время на написание этих сообщений. Будем теперь с ними разбираться.

R>1. Пугает идентификация событий и сообщений строкой:



Не тебя одного это пугает, по началу. Однако, практика показывает, что все не так страшно

R>
R>so_subscribe( "evt_hello_time", "msg_hello_time" );
R>


R>Вывод: в своём серьёзном проекте я бы не хотел видеть такие моменты — процент глупых ошибок связанных с этим при поддержке иногда доходит до 50% и больше. Самое обидное, что их мог бы отлавливать компилятор.

R>Что хотелось бы видеть: сообщения и события в виде типов, значений или ещё чего-то, что понимает компилятор. И чтобы при внесении изменений в одном месте компилятор сразу показывал возникшие проблемы в других местах.

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

Первоначально (еще в до-SObjectizer-овские времена) текстовые имена (в основном сообщений и состояний) нужны были для того, чтобы SObjectizer-приложением можно было управлять снаружи. Предполагалось, что с помошью подобного инструмента будут создаваться черные ящики, не имеющие средств диалога с пользователем. Но как-то же этими черными ящиками нужно было управлять. Причем хотелось бы, чтобы диалоговые программы для управления можно было писать не только на C++, но и на, к примеру, Visual Basic-е, Java или Python-е. Собственно, в прародителе SObjectizer-а (SCADA Objectizer) это даже было проделано. Был простенький тектовый протокол, названный SOP, который позволял отсылать в черный ящик сообщения, команды на смену состояния агента или запросы на получение состояния агента. Java-клиент с GUI интерфейсом подключался к черному ящику и мог с помощью SOP управлять черным ящиком.

Мне это показалось настолько удобно, что в SObjectizer я решил оставить использование текстовых имен для всех основных понятий (классов агентов, имен агентов, имен сообщений, состояний, событий). С одной стороны, это нужно для того, чтобы SObjectizer приложения могли обмениваться данными между собой (через SOP). С другой стороны, это нужно для того, чтобы SObjectizer RunTime мог отслеживать такие вещи, как наследование классов агентов и подписку и выдавать внятные сообщения об ошибках.

Кстати, это насколько удобно, что широко используется и сейчас. Например, для воздействия на SObjectizer-приложения во время отладки. Есть простенький инструментик, который позволяет отсылать по SOP команды в SObjectizer-приложения со стандартного ввода. Например, в отладке я использую такой SOP-файл (текстовый файл, содержащий SOP-команды) для выдачи команды на перезагрузку конфигурации компонента:
{send-msg
    {agent aag_3::smsc_map::default::a_router }
    {msg     msg_configure }
}
send
exit

Я просто запускаю:
so_send_stdin "какой-то IP" < reconfigure.sop

А вот с помощью этого ruby-скрипта при отладке имитируется поступление 5000 нужных мне сообщений:
1.upto( 5000 ) do |i|
    puts <<-EOF
{send-msg
    {agent    aag_3::smpp_smsc::bserver.trx::a_channel }
    {msg    msg_imit_delivery_receipt }
    {field    m_short_message
        {string-stream "id:#{i} sub:001 dlvrd:001 submit date:0508251625 done date:0508251625 stat:DELIVRD err:000 text:AAG3 test"} }
}
    EOF
    puts "send" if 0 == i % 10
end

puts "exit"

запускается это дело так:
ruby imit_delivery_receipt.rb | so_send_stdin "какой-то IP"

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

Так что было желание сохранить идентификацию основых понятий с помощью строк. Задача была в том, чтобы сократить количество строковых литералов в C++ коде и по максимому задействовать статическую типизацию. Где-то это удалось сделать. Например, при описании класса агента для SObjectizer строковых литералов нет (за исключением всего, что связано с описанием состояний). Имена классов, типов сообщений и имена событий должны быть корректными C++ идентификаторами. Например, попытка указать в SOL4_EVENT имя не существующего метода приведет к ошибке еще во время компиляции.

Но вот с именами сообщений и с моментом подписки все не так просто. Все дело в том, что в C++ нет никакой рефлексии, поэтому возникает вопрос о том, как, например, связать текстовое имя сообщения (которое необходимо для SOP) с C++ идентификатором типа сообщения. Можно было бы попробовать воспользоваться RTTI для получения из имени типа текстовое сообщение. Но, насколько я знаю, в разных компиляторах RTTI строит разные текстовые имена для одного и того же типа. А в SObjectizer требовалось, чтобы по SOP можно было связать несколько процессов, скомпилированных разными компиляторам. Поэтому RTTI не подошел. Далее можно было бы рассмотреть способ вроде такого:
struct msg_hello_time {
  static const std::string so_msg_name = "msg_hello_time";
  ...
};

Но заставлять пользователя подобные конструкции не очень хорошо, т.к. слишком много писанины. Ну и не все компиляторы в свое время поддерживали описание static const в определении класса/структуры. Получалось, что попытка как-то связать имя типа с именем сообщения в C++ приведет к использованию макросов. Макросов же в SObjectizer и так не мало. Лишние без необходимости вводить не хотелось.

И еще один важный фактор. Один и тот же тип мог использоваться сообщений с разными именами. Это не так уж и редко делается на практике. Вот и не нашлось удобного способа использовать в коде программы C++ идентификаторы, который каким-то образом преобразовывал идентификатор (имя типа) в строку.

С идентификацией имен событий вообще плохо, т.к. событие -- это метод. А с идентификатором имени метода в C++ вообще не много чего можно сделать.

Так что получалось, что код мог выглядеть как-то так:
so_subscribe( SO4_EVENT_NAME( a_hello_t, evt_hello_time ), SO4_MSG_NAME( msg_hello_time ) );

но лично мне такая запись не нравится.

Далее, так ли плохи строковые идентификаторы? Вообще-то говоря, они дают возможность управлять подпиской в run-time. Если бы я написал в C++ коде что-то вроде:
subscribe< msg_hello_time >( &a_hello_t::evt_hello_time );

то намертво бы закрепил связь между сообщением msg_hello_time и evt_hello_time. Но как связать evt_hello_time с другим сообщением в run-time? Подобная статическая связанность была в последней версии SCADA Objectizer и являлась чуть ли не самым большим недостатком, т.к. на практике требовалось динамически менять подписку, причем имя сообщения (а иногда и события) могло стать известно только в run-time.

Использование же тестовых идентификаторов подобную свободу предоставляет. Например, после своего старта агент может прочитать какой-нибудь конфиг и узнать, на сообщения каких агентов ему следует подписать свои события. Либо агент может среагировать на какое-то событие, узнать о появлении нового агента и подписаться на его сообщения (так, например, делает агент-коммуникатор при появлении нового глобального агента). Более того, подобную подписку может делать не только сам агент, но кто-либо другой, какой-нибудь конфигуратор, даже не являющийся агентом.

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

Теперь о страхах и вероятности все запортить связав не то не с тем. Очевидно, что SObjectizer позволяет наломать дров. Но в SObjectizer предпринимаются некоторые шаги для повышения безопасности. Во-первых, использование макроса SO4_EVENT_STC(evt_name, msg_name) указывает SObjectizer, что evt_name будет получать только сообщения типа msg_name. И эта информация позволяет в so_subscribe проверить типа сообщения на которое подписывается сообщение. И, если у сообщения другой тип, то подписка не выполняется. Однако, в момент отсылки сообщения SObjectizer не в состоянии проверить тип указателя, передаваемый в send_msg(). Поэтому, если пользователь отослал агенту сообщение не того типа, то SObjectizer помочь здесь не сможет. Ну это обычная ситуация в C++ приложениях при передаче информации через void*. Если же попробовать отказаться от void*, то тогда агент лишается возможности подписать свое событие на несколько разнотипых сообщений. А иногда это нужно. Например, агенту-коммуникатору. Или прикладному агенту, которому не столь важны данные в сообщении, сколько сам факт наличия сообщения.

Во-вторых, при подписке события SObjectizer проверяет наличие в словаре имен событий и сообщений. Поэтому попытка пописать несуществующее сообщение или несуществующее событие завершается возникновением ошибки. А поскольку в большинстве случаев подписка выполняется в одном централизованном методе so_on_subscription(), то ошибки подписки сразу становятся заметны.

Ну и что получается на практике. Самой распространенной проблемой с подпиской события является отсутствие подписки события. Т.е. элементарно забывают пописать событие. Так что проблемы с тем, что что-то не на то подписали, на практике практически не встречалась.

Так же нет проблем с сопровождением строковых литералов. Этому способствует использование нотации: префикс evt_ для имен событий и msg_ для имен сообщений. Поэтому такие распространенные имена, как status в качестве имен событий/сообщений практически не встречаются. Если же возникает необходимость сменить имя события, например, с evt_hello_time на evt_yet_another_hello, то в коде все равно следует искать подстроку evt_hello_time, а затем уже на месте смотреть, нужно ли это вхождение или следует искать дальше. И здесь уже без разницы, является ли найденная подстрока частью идентификатора или строкового литерала. То, что компилятор не сможет проверить корректность имен событий/сообщений -- это не приятно. Но выручают проверки, выполняемые самим SObjectizer. Так что на практике проблем с сопровождением строковых литералов не было.

R>Приём сообщения:


R>
R>void process(const TextChangedEvent& e);
R>


R>Эта же строчка обеспечивает подписку.


Кстати, не расскажешь, как именно декларация функции/метода может обеспечить автоматическую подписку?


SObjectizer: <микро>Агентно-ориентированное программирование на C++.
Re[2]: Конструктивная критика 2
От: eao197 Беларусь http://eao197.blogspot.com
Дата: 02.04.06 13:26
Оценка:
Здравствуйте, remark, Вы писали:

R>2. Всю документацию полностью не прочитал, но как я понял все сообщения в системе идут через единый коммутатор. В MPI (я так понял, ты с ним знаком) есть понятие коммутаторов, т.е. сущностей, которые принимают, маршрутизируют и отправляют сообщения. Для крупной системы имело бы смысл иметь несколько коммутаторов. Как с т.з. производительности, так и с т.з. логики работы. Коммутаторы могут иметь отношение к абсолютно разным частям системы — один к ui, другой к БД, другой к бизнес-логике, другой к инфраструктуре приложения. И зачем подсистеме ui иметь возможность принимать сообщения связанные с БД непонятно.


Вообще-то агент-коммуникатор обслуживает только сообщения глобальных агентов. Он занимается их маршаллингом/демаршалингом.
В приложении может быть только один SObjectizer Run-Time, который занимается диспетчеризацией всех сообщений. Може ты его имел в виду под единым коммутатором?

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

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

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


SObjectizer: <микро>Агентно-ориентированное программирование на C++.
Re[2]: Конструктивная критика 3
От: eao197 Беларусь http://eao197.blogspot.com
Дата: 02.04.06 13:50
Оценка:
Здравствуйте, remark, Вы писали:

R>3. Состояния и агент являются монолитом. Агент находится сразу во всех состояниях по крайне мере в том смысле, что он должен содержать все данные, которые нужны всем его состояниям. Это плохо, т.к. (1) нелогично, (2) может привидить к ошибкам (когда агент обращается к своей переменной-члену, которая логически не имеет смысл в текущем состоянии агента, но физически она существует) и (3) может быть расточительно (данные одного состояния большие, но требуются очень редко).


Вот с этим пунктом не согласен категорически. Особенно с пунктами (1) /видимо у меня логика другая / и (2).

Агент -- это прежде всего объект. Состояние определяет не то, из чего агент будет состоять, а то, как агент будет реагировать на внешние события. И, опять же из практики, агенту часто нужны все его составляюшие, чтобы корректно работать в очередном состоянии. Например, агент может отвечать за транспортировку транзакций на удаленную сторону. В состояние st_connected (когда есть соединение с удаленной стороной) агент берет транзакции из своей внутренней очереди и отправляет их в канал. Когда связи нет, состояние st_disconnected, агент может ставить новые транзакции в очередь (если там есть место) в надежде отослать их в канал при восстановлении соединения. А может и переодически пересканировать список транзакций и вычеркивать самые старые.

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

Если же есть проблемы с потреблением ресурсов (что, вообще-то говоря не так уж и вероятно), то при смене состояния можно очищать или создавать ресурсы заново (благо в SObjectizer можно вешать обработчики на вход в состояние и выход из состояния). При этом время на создание/удаление ресурсов ты будешь тратить в случаях, когда это действительно необходимо.

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

R>На данный момент при описании SOL4_CLASS_START присутствует дублирование и описание не так явно — ты писал в недостатках, что иногда забывают добавлять что-то в описание агента. При моём предложенном подходе, такие забывания сократились бы, т.к. не надо "при добавлении сюда, не забыть добавить туда".


Ты забываешь один момент: в C++ синтаксисе не достаточно средств для того, чтобы выразить все, что необходимо SObjectizer. В частности, привязывание событий к состояниям и наследование событий/состояний из разных классов агентов. Поэтому что-то вроде SOL4_CLASS_START все равно потребовалось бы. И проблема дублирования описаний и там и там все равно бы осталась. Нет, конечно, можно что-нибудь в духе метапрограммирования на шаблонах замутить. Но мои попытки придумать что-либо подобное приводило к слишком уж сложным и неудобным в использовании наворотам. Причем именно с точки зрения пользователя SObjectizer получалось не очень удобно и декларативно, описания в SOL4_CLASS_* выглядели по сравнению с шаблонами гораздо проще, понятнее и декларативнее.

Единственный реальный выход из этого я вижу в использовании специализированного DSL, из описания на котором будут автоматически генерироваться, как минимум:
— фрагменты C++ кода для размещения в декларации класса агента;
— все содержимое описания класса агента для SObjectizer (все, что между макросами SOL4_CLASS_START/SOL4_CLASS_FINISH).
Возможно, что из такого описания можно будет генерировать метод so_on_subscription и заглушки для методов-событий.
В качестве проверки такой кодогенерации был затеян проект RuCodeGen
Автор: eao197
Дата: 16.11.05
. Пока нет точного определения самого DSL (только приблизительные наметки).

R>Так же возможно (не знаю, насколько это реально) повторное использование состояний. Т.е. Агенты и состояния становятся перпендикулярными, и для агента можно просто набрать множество уже готовых состояний — и вот новый агент.


Для этого можно использовать обычное множественное наследование, имхо.


SObjectizer: <микро>Агентно-ориентированное программирование на C++.
Re[2]: Конструктивная критика 4
От: eao197 Беларусь http://eao197.blogspot.com
Дата: 02.04.06 14:33
Оценка:
Здравствуйте, remark, Вы писали:

R>4. Синхронные сообщения — всё-таки они нужны. Их отсутствие сужает область применения, если не в два раза, то по крайней мере на треть.


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

R>Иногда надо вернуть какой-то результат. Без этого теряется весь смысл. Т.е. подписчик на сообщение должен не только сделать что-то сам, но и сообщить что-то издателю.


Сейчас это делается отсылкой ответного сообщения.

R>Самые простые примеры — есть контрол с текстом, и есть подписчики-валидаторы, которые при изменении текста должны его проверить и сообщить результат.


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

R>Или какое-то важное сообщение (оповещение о завершении работы приложения).


А в чем проблема в использовании для этого дела асинхронного сообщения?

R>Или взять например систему сообщений Windows — там всегда предусмотрена возможность вернуть результат обработки.


Насколько я помню, использование SendMessage в Win32 для взаимодействия нескольких потоков или приложений -- это не самый удобный и рекомендуемый вариант работы.

R>У вас при использовании SObjectizer просто всегда есть возможность сделать обычный статический вызов при необходимости получить результат, а что если бы её не было? Или объект, у которого вызывается метод, надо перенести на другую машину? В случае, если имеется sync_send никаких доработок не понадобиться.


Как раз в SObjectizer все достаточно строго: либо работаешь только через сообщения, тогда вообще нет никаких проблем с расщеплением приложения на отдельные процессы. Либо идешь в обход SObjectizer, через те же статические методы и получается тесная взаимосвязь между компонентами.

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

R>Проблемы с потоками вполне можно решить: отправитель сообщения всегда работает в своём потоке, а инфрастуктура отдаёт сообщение диспетчеру и ждёт ответа, далее возвращает ответ вызвавшему потоку. При этом с т.з. кто в каком потоке работает выглядит всё точно так же как при асинхронном сообщении.


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

Кроме того, что я не придумал простого способа подобных повторных входов/выходов (а над сложным думать было некогда ), есть еще и другие белые пятна. Например, предположим, что есть агент A, к которому стоят заявки a2, b1, c0 (цифра -- это приоритет). Во время обработки a2 агент A синхронно обращается к агенту B, но агент B должен обработать это обращение на той же нити. Получится, что в очереди рабочей нити стоят заявки b1(A), c0(A) и d0(B) /в скобках показан агент, которому принадлежит событие/. Когда рабочая нить повторно начнет выборку событий из своей очереди окажется, что события b1(A) и c0(A) извлекать и обрабатывать нельзя, т.к. они менее приоритетны события a2 и не могут быть обработаны до завершения обработки a2. Такие нюансы, во-первых, усложняют систему диспетчеризации, во-вторых, увеличивают накладные расходы на нее (в особенности на поиск и преодоление дедлоков). И, в-третьих, как мне кажется, способны только усложнить проектирование приложений в SObjectizer.

R>По поводу дедлоков — тут никуда не деться, тут они всегда были и остануться.


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


R>Фактически сейчас есть возможность отправлять синхронные сообщения:


R>
R>struct SyncMessageParams
R>{
R>    int result;
R>    Event messageProcessed; // Событие, что сообщение обработано
R>    void wait(); // Ждать, пока сообщение не обработается
R>};

R>SyncMessageParams params;
R>async_send("msg", &params);
R>params.wait(); // Ждём пока сообщение будет обработано
R>if (params.result) ...;
R>


Это не правильный код
Сообщения должны быть динамически созданными объектами, удалением которых занимается сам SObjectizer.

R>Тока единственная проблема — только инфрастуктура может знать, что все подписчики обработали сообщение, и установить Event messageProcessed.

R>Поэтому нужна хотя бы минимальная поддержка со стороны инфрастуктуры — чтобы она установила Event после того как всё подписчики обработают сообщение. Необходимость такого действия можно определять например так: если параметры сообщения отнаследованы от некого SyncParams, то значит сообщение синхронное и надо установить этот Event.

Настораживает меня фраза "все подписчики обработали сообщение". Имхо, если речь заходит о синхронном взаимодействии. то оно не может быть широковещательным, а только целенаправленным (адресным).

Мне бы виделось использование синхронности в каком-то таком виде:
// Инициатор синхронного сообщения.
so_4::rt::sync_response_t< msg_response > resp;
if( !so_4::api::send_msg_safely( some_agent, "msg_do_this", request, receiver_name, resp ) )
  {
    // Сообщение отправлено. Можно ждать результата.
    ...
    if( !resp.wait() )
      // Результат получен. Обрабатываем его.
      ...
    else // Произошла ошибка получения результата.
      ...
  }
else // Произошла ошибка отсылки синхронного сообщения.
  ...

// Код обработчика синхронного сообщения.
void
evt_do_this(
  so_4::rt::event_data_t & event_data,
  const msg_do_this & cmd )
  {
    // Обработка.
    ...
    // Отсылка ответа.
    event_data.reply( new msg_response( ... ) );
    ...
  }


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


SObjectizer: <микро>Агентно-ориентированное программирование на C++.
Re[3]: Конструктивная критика 1
От: remark Россия http://www.1024cores.net/
Дата: 02.04.06 21:18
Оценка:
Здравствуйте, eao197, Вы писали:

R>>1. Пугает идентификация событий и сообщений строкой:


E>Не тебя одного это пугает, по началу. Однако, практика показывает, что все не так страшно


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



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


E>
E>1.upto( 5000 ) do |i|
E>    puts <<-EOF
E>{send-msg
E>    {agent    aag_3::smpp_smsc::bserver.trx::a_channel }
E>    {msg    msg_imit_delivery_receipt }
E>    {field    m_short_message
E>        {string-stream "id:#{i} sub:001 dlvrd:001 submit date:0508251625 done date:0508251625 stat:DELIVRD err:000 text:AAG3 test"} }
E>}
E>    EOF
E>    puts "send" if 0 == i % 10
E>end

E>puts "exit"
E>



А вот тут можно поподробнее. Выделенная строка это что? Это кто будет парсить? Или это никто не будет парсить, это и есть сообщение в том виде, в котором оно попадёт в метод-обработчик события?

Сюда же вопрос — если я извне посылаю сообщение, то строковый идентификатор соообщения указать не проблема, но как создать объект с параметрами?
Объект создаёт рантайм SO на основе этого:
SOL4_MSG_START(msg_alarm, msg_alarm)
  SOL4_MSG_FIELD(m_sensor_name)
  SOL4_MSG_FIELD(m_current_value)
  SOL4_MSG_FIELD(m_max)
SOL4_MSG_FINISH()

?

Если это так, то это очень грамотно




E>Подобная статическая связанность была в последней версии SCADA Objectizer и являлась чуть ли не самым большим недостатком, т.к. на практике требовалось динамически менять подписку, причем имя сообщения (а иногда и события) могло стать известно только в run-time.


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



E>Ну и еще, вероятно, сказалось то, что я не являюсь фанатичным стороником статической типизации. Имхо, некоторая доля динамизма в статически типизированной программе не помешает


Такое подозрение у меня уже возникло
А как насчёт SmallTalk? Ваша система, по-моему, достаточно похожа на работу объектов в SmallTalk? Только там асинхронности не хватает.



E>Или прикладному агенту, которому не столь важны данные в сообщении, сколько сам факт наличия сообщения.



А как насчёт наследования строковых идентификаторов?
У меня была такая идея:

struct SMSStateChange: Event {};
struct SMSReceivedEvent: SMSStateChange{};
struct SMSSavedToDBEvent: SMSStateChange{};


Соответственно кто-то может подписаться на:

void subscrive(SMSSavedToDBEvent& e);


А кто-то просто:

void subscrive(SMSStateChange& e);


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





R>>Приём сообщения:


R>>
R>>void process(const TextChangedEvent& e);
R>>


R>>Эта же строчка обеспечивает подписку.


E>Кстати, не расскажешь, как именно декларация функции/метода может обеспечить автоматическую подписку?


У меня на шаблонах было. Т.е. генерация кода во время компиляции — я с помощью SFINAE проверяю наличие данного метода. Допустим надо сгенерировать код для реакции объекта класса SomeClass на событие SomeEvent. Я проверял наличие метода:
void SomeClass::process(SomeEvent&);




1024cores &mdash; all about multithreading, multicore, concurrency, parallelism, lock-free algorithms
Re[3]: Конструктивная критика 2
От: remark Россия http://www.1024cores.net/
Дата: 02.04.06 21:20
Оценка:
Здравствуйте, eao197, Вы писали:

E>Наличие же единственного SObjectizer Run-Time, с другой стороны, сильно упрощает использование SObjectizer. Не болит голова о том, в каком Run-Time агент зарегистрирован, в какой Run-Time нужно отсылать сообщения. И нет вопросов о том, что делать, если агент должен одновременно входить в несколько Run-Time.



В MPI не понятия вхождения агента в коммутатор. Да собственно нужно ли оно? Просто при отсылке сообщения можно указать идентификатор коммутатора.


1024cores &mdash; all about multithreading, multicore, concurrency, parallelism, lock-free algorithms
Re[3]: Конструктивная критика 3
От: remark Россия http://www.1024cores.net/
Дата: 02.04.06 22:25
Оценка:
Здравствуйте, eao197, Вы писали:

E>Здравствуйте, remark, Вы писали:


R>>3. Состояния и агент являются монолитом. Агент находится сразу во всех состояниях по крайне мере в том смысле, что он должен содержать все данные, которые нужны всем его состояниям. Это плохо, т.к. (1) нелогично, (2) может привидить к ошибкам (когда агент обращается к своей переменной-члену, которая логически не имеет смысл в текущем состоянии агента, но физически она существует) и (3) может быть расточительно (данные одного состояния большие, но требуются очень редко).


E>Вот с этим пунктом не согласен категорически. Особенно с пунктами (1) /видимо у меня логика другая / и (2).


E>Агент -- это прежде всего объект. Состояние определяет не то, из чего агент будет состоять, а то, как агент будет реагировать на внешние события. И, опять же из практики, агенту часто нужны все его составляюшие, чтобы корректно работать в очередном состоянии. Например, агент может отвечать за транспортировку транзакций на удаленную сторону. В состояние st_connected (когда есть соединение с удаленной стороной) агент берет транзакции из своей внутренней очереди и отправляет их в канал. Когда связи нет, состояние st_disconnected, агент может ставить новые транзакции в очередь (если там есть место) в надежде отослать их в канал при восстановлении соединения. А может и переодически пересканировать список транзакций и вычеркивать самые старые.


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



Состояние, конечно, в первую очередь определяет поведение. Но для реализации поведения данного состояния могут понадобиться данные.
В твоём примере очередь должна относиться не к состоянию, а к самому объекту. А вот канал относится уже исключительно к состоянию st_connected.
А что будет, если я в состоянии st_disconnected вызову какой-то метод канала — ничего хорошего. И это логическая ошибка. Т.е. прграммист скорее всего не хотел это написать — не хотел, что бы в состоянии st_disconnected происходили какие-либо вызовы канала.
Задача хорошего дизайна — отлавливать логические ошибки на этапе компиляции.
А если состояние — это объект, то мы как раз уменьшаем область видимости данных только до той, где они реально нужны и могут использоваться.
Ну как, например, когда автоматическую переменную мы помещаем в блок {}, если кто-то попытается обратиться к этой переменной за пределами блока, то компилятор сообщит об ошибке.
С состояниями, мне кажется, имеет место такая же ситуация.



E>Если же есть проблемы с потреблением ресурсов (что, вообще-то говоря не так уж и вероятно), то при смене состояния можно очищать или создавать ресурсы заново (благо в SObjectizer можно вешать обработчики на вход в состояние и выход из состояния). При этом время на создание/удаление ресурсов ты будешь тратить в случаях, когда это действительно необходимо.


E>В подходе, предложенном тобой пересоздание ресурсов происходит всегда при смене состояния. Даже тогда, когда в этом нет необходимости.


Согласен.
Но опять же, будет ли постоянное создание/уничтожение ресурсов создавать проблемы с производительностью. Вообще программиста это не должно волновать. Пусть он вначале пишет прозраный и логичный код. А потом, если что, можно будет вынести ресурс, который дорого создавать/рушить, с уровня состояния, до уровня самого объекта (с соответствующим комментарием).





E>Единственный реальный выход из этого я вижу в использовании специализированного DSL, из описания на котором будут автоматически генерироваться, как минимум:

E>- фрагменты C++ кода для размещения в декларации класса агента;
E>- все содержимое описания класса агента для SObjectizer (все, что между макросами SOL4_CLASS_START/SOL4_CLASS_FINISH).
E>Возможно, что из такого описания можно будет генерировать метод so_on_subscription и заглушки для методов-событий.
E>В качестве проверки такой кодогенерации был затеян проект RuCodeGen
Автор: eao197
Дата: 16.11.05
. Пока нет точного определения самого DSL (только приблизительные наметки).



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



1024cores &mdash; all about multithreading, multicore, concurrency, parallelism, lock-free algorithms
Re[3]: Конструктивная критика 4
От: remark Россия http://www.1024cores.net/
Дата: 02.04.06 22:34
Оценка:
Здравствуйте, eao197, Вы писали:


R>>Самые простые примеры — есть контрол с текстом, и есть подписчики-валидаторы, которые при изменении текста должны его проверить и сообщить результат.


E>Кстати, не удачный пример. Взаимодействие посредством сообщений слишком дорогая операция, чтобы делать с помощью SObjectizer-а валидацию текста в контроле. Это как раз отличный пример того, для чего SObjectizer не имеет смысла использовать.


Я имел в виду не пример применения SObjectizer, а пример, где не обойтись без синхронности.



R>>Или какое-то важное сообщение (оповещение о завершении работы приложения).


E>А в чем проблема в использовании для этого дела асинхронного сообщения?


Забавно. Типа "ну вы вообще конечно начинайте готовиться к завершению программы, но процесс всё равно умрёт неожиданно"





E>Кроме того, что я не придумал простого способа подобных повторных входов/выходов (а над сложным думать было некогда ), есть еще и другие белые пятна. Например, предположим, что есть агент A, к которому стоят заявки a2, b1, c0 (цифра -- это приоритет). Во время обработки a2 агент A синхронно обращается к агенту B, но агент B должен обработать это обращение на той же нити. Получится, что в очереди рабочей нити стоят заявки b1(A), c0(A) и d0(B) /в скобках показан агент, которому принадлежит событие/. Когда рабочая нить повторно начнет выборку событий из своей очереди окажется, что события b1(A) и c0(A) извлекать и обрабатывать нельзя, т.к. они менее приоритетны события a2 и не могут быть обработаны до завершения обработки a2. Такие нюансы, во-первых, усложняют систему диспетчеризации, во-вторых, увеличивают накладные расходы на нее (в особенности на поиск и преодоление дедлоков). И, в-третьих, как мне кажется, способны только усложнить проектирование приложений в SObjectizer.


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





E>Настораживает меня фраза "все подписчики обработали сообщение". Имхо, если речь заходит о синхронном взаимодействии. то оно не может быть широковещательным, а только целенаправленным (адресным).


Почему? Опять же пример с валидацией текста.



1024cores &mdash; all about multithreading, multicore, concurrency, parallelism, lock-free algorithms
Re[4]: Конструктивная критика 1
От: eao197 Беларусь http://eao197.blogspot.com
Дата: 03.04.06 06:44
Оценка:
Здравствуйте, remark, Вы писали:

R>В целом я понял. Да, если будет типизация, то не будет связи с внешними системами, и не будет возможности отсылать сообщения в систему вручную.


Вот именно.

E>>
E>>1.upto( 5000 ) do |i|
E>>    puts <<-EOF
E>>{send-msg
E>>    {agent    aag_3::smpp_smsc::bserver.trx::a_channel }
E>>    {msg    msg_imit_delivery_receipt }
E>>    {field    m_short_message
E>>        {string-stream "id:#{i} sub:001 dlvrd:001 submit date:0508251625 done date:0508251625 stat:DELIVRD err:000 text:AAG3 test"} }
E>>}
E>>    EOF
E>>    puts "send" if 0 == i % 10
E>>end

E>>puts "exit"
E>>


R>А вот тут можно поподробнее. Выделенная строка это что? Это кто будет парсить? Или это никто не будет парсить, это и есть сообщение в том виде, в котором оно попадёт в метод-обработчик события?


Тег {string-stream} — это часть текстового представления SOP-а, его парсит so_send_stdin. А значение в ковычках -- это значение для поля m_short_message. Именно таким оно и придет во внутрь приложения. Для того, чтобы это дело работало, атрибут msg_imit_delivery_receipt::m_short_message должен иметь в C++ программе тип std::string или char[].

R>Сюда же вопрос — если я извне посылаю сообщение, то строковый идентификатор соообщения указать не проблема, но как создать объект с параметрами?

R>Объект создаёт рантайм SO на основе этого:
R>
R>SOL4_MSG_START(msg_alarm, msg_alarm)
R>  SOL4_MSG_FIELD(m_sensor_name)
R>  SOL4_MSG_FIELD(m_current_value)
R>  SOL4_MSG_FIELD(m_max)
R>SOL4_MSG_FINISH()
R>

R>?

R>Если это так, то это очень грамотно


Это так. Для каждого сообщения задекларированного через SOL4_MSG_START/FINISH рантайм умеет создавать динамически объекты по необходимости (при получении этого сообщения по SOP). Отсюда и ограничения: сообщение в SObjectizer должно иметь конструктор по-умолчанию. В динамически созданный объект сообщения SObjectizer способен помещать значения полей, перечисленных в макросах SOL4_MSG_FIELD. Собственно, эти макросы и нужны для того, чтобы сделать сообщение доступным через SOP.

E>>Подобная статическая связанность была в последней версии SCADA Objectizer и являлась чуть ли не самым большим недостатком, т.к. на практике требовалось динамически менять подписку, причем имя сообщения (а иногда и события) могло стать известно только в run-time.


R>Да, тут со строками действительно проще.

R>Хотя я не очень понимаю, как агент может реагировать на сообщения/события, для которых не написан код во время разработки.

Код должен быть написан, это понятно. Но есть несколько моментов:
* агент-коммуникатор способен работать с любыми сообщениями для маршаллинга/демаршаллинга, используя для этого информацию из системного словаря SObjectizer;
* некий агент способен обрабатывать разнотипные сообщения, если ему не важно содержимое этих сообщений, а важен сам факт их наличия;
* в некоторых случаях агент способен обрабатывать сообщения, производные от некоторого базового типа (обычный полиморфизм и работа через базовый интерфейс).

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

R>А как насчёт SmallTalk? Ваша система, по-моему, достаточно похожа на работу объектов в SmallTalk? Только там асинхронности не хватает.


Со SmallTalk-ом я, к сожалению, знаком очень поверхностно, ничего не писал на нем.
Но похожая схема не только в SmallTalk, но и в Ruby.

R>А как насчёт наследования строковых идентификаторов?

R>У меня была такая идея:
<...код поскипан...>
R>Я так понимаю. что когда ты говоришь "важен сам факт наличия сообщения, а данные не важны", то фактически это означет, что важна реакция на некий базовый тип сообщения, а не на производный.

Вероятно ты говоришь третьем варианте (с полиморфизмом), который я описал чуть выше.


SObjectizer: <микро>Агентно-ориентированное программирование на C++.
Re[4]: Конструктивная критика 2
От: eao197 Беларусь http://eao197.blogspot.com
Дата: 03.04.06 07:16
Оценка:
Здравствуйте, remark, Вы писали:

E>>Наличие же единственного SObjectizer Run-Time, с другой стороны, сильно упрощает использование SObjectizer. Не болит голова о том, в каком Run-Time агент зарегистрирован, в какой Run-Time нужно отсылать сообщения. И нет вопросов о том, что делать, если агент должен одновременно входить в несколько Run-Time.


R>В MPI не понятия вхождения агента в коммутатор. Да собственно нужно ли оно? Просто при отсылке сообщения можно указать идентификатор коммутатора.


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

Итак, кто-то вызывает send_msg. SObjectizer блокирует свой системный словарь в режиме read-only, проверяет наличие сообщения в системе. Если сообщение есть, то создается экземпляр заявки. После этого системный словарь разблокируется, а заявка передается диспетчеру, который помещает ее в нужную очередь.

Все. Диспетчеризация, как видишь, происходит в месте вызова send_msg. И, поскольку системный словарь блокируется на небольшое время, да еще в read-only режиме (т.е. допускается параллельная обработка send_msg), то особых затрат на диспетчеризацию нет (есть еще блокировка на уровне диспетчера, но она зависит от типа диспетчера).

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


SObjectizer: <микро>Агентно-ориентированное программирование на C++.
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.