Автор Тема: [CP] Вопрос про Message Bus.  (Прочитано 10455 раз)

valexey_u

  • Hero Member
  • *****
  • Сообщений: 3013
    • Просмотр профиля
Re: [CP] Вопрос про Message Bus.
« Ответ #15 : Февраль 02, 2013, 09:11:36 am »
Вопрос собственно, наверно к Илье Ермакову: правильно ли я понимаю, что в в случае Message Bus, все сообщения сидят на стеке? Или они все же в массивах где-то в куче обитают?

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

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

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

То есть это выглядит примерно так?
PROCEDURE MessageSender
VAR
    msg : RECORD (GenericMessage) myField : INTEGER; processed : BOOLEAN END;
    i : INTEGER;
BEGIN
    msg.myField := 42;
    msg.processed := FALSE;
    WHILE i<LEN(Handlers) & ~msg.processed DO
        Handlers[i](msg);
        i := i+1;
    END;
END MessageSender;

Но тогда я не понимаю тезис про нагрузку на сборщик мусора - ведь при такой модели использования можно просто в куче создать по одному сообщению каждого типа и просто из повторно использовать. Даже если у нас типов сообщений действительно многого, штук 100, то все равно никакой значимой нагрузки на GC не будет. Да и аллокаций памяти не будет тоже.
Y = λf.(λx.f (x x)) (λx.f (x x))

X512

  • Newbie
  • *
  • Сообщений: 45
    • Просмотр профиля
Re: [CP] Вопрос про Message Bus.
« Ответ #16 : Февраль 02, 2013, 09:44:01 am »
То есть это выглядит примерно так?
Примерно так. Только в BlackBox нигде processed и аналогов не используются. Сообщения шлются либо конкретно заданному объекту, либо всем видимым отображениям с заданной моделью (тупо перебираются все фреймы окна и сравнивается модель), либо всем отображениям, которые находятся в пути фокуса. Есть ещё другие специфичные варианты, здесь их рассматривать не будем. При посылке конкретно заданному объекту процедура посылки, это лишь небольшая обёртка, выполняющая проверки и прочие мелкие операции, например процедура посылки сообщения свойств:
PROCEDURE HandlePropMsg* (v: View; VAR msg: PropMessage);
VAR a: View; op: INTEGER;
BEGIN
IF ~(handler IN v.bad) THEN (* проверяем, что в раньше в обработчике v не было TRAP'а *)
a := actView; op := actOp; actView := v; actOp := handler; (* запоминаем отображение и тит обработчика *)
v.HandlePropMsg(msg); (* вызываем обработчик *)
actView := a; actOp := op (* возвращаем всё как было *)
END
END HandlePropMsg;

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

Тоесть имеется ввиду что-то вроде:
TYPE MouseMovedMsg* = POINTER TO RECORD x, y: INTEGER END; (* встроить тип в VAR нельзя, иначе нельзя будет привести к нему сообщение *)
VAR mouseMoved: MouseMovedMsg;

PROCEDURE SendMouseMoved*(t: Target; x, y: INTEGER);
BEGIN
  mouseMoved.x := x; mouseMoved.y := y;
  t.Handle(mouseMoved)
END SendMouseMoved;

BEGIN
  NEW(mouseMoved)
?
Такой подход может не сработать, если обработчик рекурсивно шлёт сообщение того-же типа. Да и громоздко всё это, но впринципе работать будет, если добавить проверки на вложенную посылку сообщений.

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

X512

  • Newbie
  • *
  • Сообщений: 45
    • Просмотр профиля
Re: [CP] Вопрос про Message Bus.
« Ответ #17 : Февраль 02, 2013, 09:47:25 am »
Насчёт тезисов: вы меньше OberonCore'а читайте, они пропогандируют то, что сами не понимают. Пытаются умолчать недостатки не понимая преемуществ.

valexey_u

  • Hero Member
  • *****
  • Сообщений: 3013
    • Просмотр профиля
Re: [CP] Вопрос про Message Bus.
« Ответ #18 : Февраль 02, 2013, 10:06:53 am »
То есть это выглядит примерно так?
Примерно так. Только в BlackBox нигде processed и аналогов не используются.
Ну, я просто пытался прикинуть зачем нужна может быть модификация сообщения обработчиком. По видимому, она может быть нужна для посылки ответа тому кто послал. Что я и смоделировал в простейшем случае.

Тоесть имеется ввиду что-то вроде:
TYPE MouseMovedMsg* = POINTER TO RECORD x, y: INTEGER END; (* встроить тип в VAR нельзя, иначе нельзя будет привести к нему сообщение *)
VAR mouseMoved: MouseMovedMsg;

PROCEDURE SendMouseMoved*(t: Target; x, y: INTEGER);
BEGIN
  mouseMoved.x := x; mouseMoved.y := y;
  t.Handle(mouseMoved)
END SendMouseMoved;

BEGIN
  NEW(mouseMoved)
?
Такой подход может не сработать, если обработчик рекурсивно шлёт сообщение того-же типа. Да и громоздко всё это, но впринципе работать будет, если добавить проверки на вложенную посылку сообщений.

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

Впрочем, я кажется понимаю в чем проблема такого подхода - кто-нибудь может взять, и сохранить переданный ему указатель на сообщение для неких своих нужд. В результате получим не предсказуемое поведение - любое сообщение может быть модифицировано в любой момент времени непредсказуемым образом.
Y = λf.(λx.f (x x)) (λx.f (x x))

X512

  • Newbie
  • *
  • Сообщений: 45
    • Просмотр профиля
Re: [CP] Вопрос про Message Bus.
« Ответ #19 : Февраль 02, 2013, 10:22:45 am »
Да, имеется ввиду именно такое. На счет рекурсивной отправки - было же сказано, что и в случае стека этим лучше не пользоваться. Впрочем, для такого подхода (через кучу) это решаемая проблема - делаем фабрику повторно используемых объектов, у которой при отправке просим выдать нам свободный экземпляр сообщения данного типа.

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

Зачем делать пулы (избыточная сложность на пустом месте, к тому же добавление новых типов сообщений станет большой проблемой) я не понимаю, чем стек не угодил? Или в ваших Java/C# нет объектов на стеке и нужно делать костыли? Относительно непредсказуемого поведения: можно ведь передавать сообщение обработчику через VAR параметр, а не указатель и тогда проблем не будет. Или в Java/C# их нет?

Всё-же я не понимаю зачем использовать кучу вместо стека...
« Последнее редактирование: Февраль 02, 2013, 10:24:33 am от X512 »

valexey_u

  • Hero Member
  • *****
  • Сообщений: 3013
    • Просмотр профиля
Re: [CP] Вопрос про Message Bus.
« Ответ #20 : Февраль 02, 2013, 10:26:03 am »
Да, имеется ввиду именно такое. На счет рекурсивной отправки - было же сказано, что и в случае стека этим лучше не пользоваться. Впрочем, для такого подхода (через кучу) это решаемая проблема - делаем фабрику повторно используемых объектов, у которой при отправке просим выдать нам свободный экземпляр сообщения данного типа.

Впрочем, я кажется понимаю в чем проблема такого подхода - кто-нибудь может взять, и сохранить переданный ему указатель на сообщение для неких своих нужд. В результате получим не предсказуемое поведение - любое сообщение может быть модифицировано в любой момент времени непредсказуемым образом.
Рекурсия хоть и не рекомендуется, но и не запрещена. В BlackBox рекурсия посылок сообщений иногда используется. Зачем делать пулы (избыточная сложность на пустом месте, к тому же добавление новых типов сообщений станет большой проблемой) я не понимаю, чем стек не угодил? Или в ваших Java/C# нет объектов на стеке и нужно делать костыли? Относительно непредсказуемого поведения: можно ведь передавать сообщение обработчику через VAR параметр, а не указатель и тогда проблем не будет. Или в Java/C# их нет?
Гм. Мысль хорошая. Я буду её думать. Спасибо. Может за выходные что-то напишу.

Всё-же я не понимаю <b>зачем</b> использовать кучу вместо стека...
Я исследую применимость подобных механизмов в других языках.
Y = λf.(λx.f (x x)) (λx.f (x x))

kkk

  • Гость
Re: [CP] Вопрос про Message Bus.
« Ответ #21 : Февраль 02, 2013, 11:15:57 am »
Я на джаве такое пилил, оно даже работает, почти так же как на ББ, через синглтон-менеджер и сообщения с конструктором, хыхы.

kkk

  • Гость
Re: [CP] Вопрос про Message Bus.
« Ответ #22 : Февраль 02, 2013, 11:16:42 am »
Насчёт тезисов: вы меньше OberonCore'а читайте, они пропогандируют то, что сами не понимают. Пытаются умолчать недостатки не понимая преемуществ.
Обжигающая Правда от Профессионалов4Fun

valexey_u

  • Hero Member
  • *****
  • Сообщений: 3013
    • Просмотр профиля
Re: [CP] Вопрос про Message Bus.
« Ответ #23 : Февраль 02, 2013, 01:11:33 pm »
Насчёт тезисов: вы меньше OberonCore'а читайте, они пропогандируют то, что сами не понимают. Пытаются умолчать недостатки не понимая преемуществ.
Обжигающая Правда от Профессионалов4Fun
Боже, это же сознательное снижение уровня дискуссии!!!11 :-D

Но коль уж перешли на личности, X512, кем бы он ни был в реальности, оставляет впечатление исключительно грамотного человека использующего в повседневной работе КП вообще, и ББ в частности.
Y = λf.(λx.f (x x)) (λx.f (x x))

kkk

  • Гость
Re: [CP] Вопрос про Message Bus.
« Ответ #24 : Февраль 02, 2013, 02:39:21 pm »
Пара цитат:
Насчёт тезисов: вы меньше OberonCore'а читайте, они пропогандируют то, что сами не понимают. Пытаются умолчать недостатки не понимая преемуществ.
Вот сознательное снижение уровня.
Цитировать
пропогандируют
А вот и исключительный уровень грамотности :D
Но в главном-то он прав!

valexey_u

  • Hero Member
  • *****
  • Сообщений: 3013
    • Просмотр профиля
Re: [CP] Вопрос про Message Bus.
« Ответ #25 : Февраль 02, 2013, 07:20:18 pm »
Я на джаве такое пилил, оно даже работает, почти так же как на ББ, через синглтон-менеджер и сообщения с конструктором, хыхы.
Как там решалась обозначенная мною проблема?
Y = λf.(λx.f (x x)) (λx.f (x x))

kkk

  • Гость
Re: [CP] Вопрос про Message Bus.
« Ответ #26 : Февраль 02, 2013, 07:44:42 pm »
Да никак не решалась, сообщения нигде не хранились и создавались перед отправкой, затем передавались в синглтон где и рассылались всем зарегистрированным объектам по порядку.
В планах было ещё запилить проверку на зацикливания и прочее, но мне было решительно лень. Да и джава надоела в тот момент.

Илья Ермаков

  • Sr. Member
  • ****
  • Сообщений: 493
    • Просмотр профиля
Re: [CP] Вопрос про Message Bus.
« Ответ #27 : Февраль 02, 2013, 08:56:01 pm »
2 valexey:

Во-первых, есть механизм передачи сообщения (ещё не bus) - VAR-параметр полиморфного типа. Это можно рассматривать как средство введения, в нужный момент в нужных местах, динамического ("утиного") ООП. И название "сообщение" здесь, в принципе, уже правомерно, на аналогии с ООП Смоллтока, например - где шлётся произвольное сообщение, а объект, если может, его обрабатывает.

Традиционный bus возникает в обероновском ГУЕ - и заключается в иерархической передаче сообщения по дереву граф. объектов с помощью вызова методов с полиморфным параметром.
Никакого хранения, асинхронности и проч. тут нет - но название "шина" правомочно в силу принципа действия: "послали сообщение в среду распространения - оно там само гуляет до тех пор, пока кто-то не обработает".

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

valexey_u

  • Hero Member
  • *****
  • Сообщений: 3013
    • Просмотр профиля
Re: [CP] Вопрос про Message Bus.
« Ответ #28 : Февраль 04, 2013, 12:04:07 pm »
Илья, спасибо большое за ответы.

Но справедливости ради, вставлю пару коментариев:

Во-первых, есть механизм передачи сообщения (ещё не bus) - VAR-параметр полиморфного типа. Это можно рассматривать как средство введения, в нужный момент в нужных местах, динамического ("утиного") ООП.  И название "сообщение" здесь, в принципе, уже правомерно, на аналогии с ООП Смоллтока, например - где шлётся произвольное сообщение, а объект, если может, его обрабатывает.
Все же к утиной типизации и к сообщениям smalltalk'а это не имеет отношения. В случае утиной типизации, да и смаллтолковых сообщений нет древовидной иерархии наследования оных сообщений/типов. Наиболее близко к этому - структурная типизация. А тут у нас все же проверка идет по имени типа сообщения, а не по структуре сообщения. Это принципиальная разница.

Ну а так да, вызов любой процедуры с аргументами можно назвать посылкой сообщения данному куску кода :-) Впрочем, это уже терминологические игры.
Y = λf.(λx.f (x x)) (λx.f (x x))

Губанов Сергей Юрьевич

  • Hero Member
  • *****
  • Сообщений: 590
    • Просмотр профиля
    • Домашняя страница
Re: [CP] Вопрос про Message Bus.
« Ответ #29 : Февраль 04, 2013, 12:46:27 pm »
Впрочем, я кажется понимаю в чем проблема такого подхода - кто-нибудь может взять, и сохранить переданный ему указатель на сообщение для неких своих нужд.
Расскажу про свою библиотеку Intercom (на C#). У меня сообщение передаётся во владение. Хочешь сохраняй, не хочешь - вызывай Dispose. В Dispose объект сообщения помещается в кэш для повторного использования. Кэш в принципе бесконечный, но раз в минуту он очищается на 10%. Есть два типа диспетчеров службы доставки сообщений: однопоточный и многопоточный. Многопоточный диспетчер может доставить одному и тому же получателю несколько сообщений одновременно. Объекты-получатели для того чтобы стать получателями должны зарегистрироваться в диспетчере. При регистрации им выдаётся интеркомный адрес Intercom.Id. Это 8 байтовое число, в котором закодирован диспетчер и номер зарегистрированного объекта. Отправка сообщения осуществляется по идентификатору Intercom.Id получателя.

Intercom.SendMessage(идентификатор_получателя, указатель_на_сообщение);

Отправляемое сообщение ставится в очередь. Затем из потока(потоков) диспетчера доставляется. Получатель может разрегистрироваться, тогда во время доставки диспетчер не найдёт объекта с указанным Intercom.Id, в этом случае у сообщения будет вызван Dispose самим диспетчером. У однопоточного диспетчера реализована возможность широковещательной рассылки сообщения всем зарегистрированным в этом диспетчере подписчикам. Это сообщение диспозится самим диспетчером, получатели не должны изменять широковещательные сообщения. Сообщения бывают первого и второго сорта (приоритета). В среднем, на каждые 10 сообщений первого сорта (если они есть) будет обработано 1 сообщение второго сорта (если оно есть). Имеется встроенный неотключаемый профилировщик, который постоянно измеряет сообщения каких типов каким типам получателей сколько раз в секунду доставляются и сколько времени обрабатываются. Измеряется длина очередей (первого и второго сорта) в секундах (латентность). Скорость отправки сообщений, скорость доставки (когда система перегружена первая скорость будет больше второй, а очередь будет расти). Программа использующая Intercom знает сколько времени сообщения простаивают в очереди (латентность) и может регулировать нагрузку. Если речь о телефонных звонках, то программа может режектить лишние телефонные звонки адаптируясь под быстродействие железа, удерживая латентность (время отклика) в заданных пределах. Имеется встроенный неотключаемый контролёр, который следит за зависаниями. Если кто-то получая сообщение слишком долго не возвращает управление, то контролёр (у него отдельный поток) печатает в журнал тип сообщения, тип получателя и сколько секунд уже тянется получение сообщения, ругаясь на то, что возможно программа зависла. Через определённый большой таймаут (убедившись, что поток точно завис и терять уже нечего кроме своих цепей) контролёр делает попытку абортировать поток диспетчера с целью получить стэк трэйс того места кода где произошло зациклиливание.

namespace MeraSystems
{
  public static partial class Intercom
  {
    public static void Subscribe (Dispatcher d, Object obj);
    public static void Unsubscribe (Object obj);
    public static void SendMessage (Id intercomId, Message message);
    public static void SendSecondGradeMessage (Id intercomId, Message message);
    public static void BroadcastMessage (Dispatcher dispatcher, Message message);
    public static void BroadcastSecondGradeMessage (Dispatcher dispatcher, Message message);
    public static void Terminate ();
    public static Dispatcher CreateDispatcher (string name, SinglethreadHook hook);
    public static Dispatcher CreateDispatcher (string name, MultithreadHook hook, int minThreadCount, int maxThreadCount);
    public static void WriteReport (System.Collections.Generic.List<string> report); // отчёт профилировщика
  }
}