LINUX.ORG.RU

Обновился инструмент для работы с агентами в C++: SObjectizer 5.5.5

 , , ,


1

2

SObjectizer — это небольшой фреймворк для упрощения разработки многопоточных приложений на C++. SObjectizer позволяет создавать объекты-агенты, которые взаимодействуют друг с другом только посредством асинхронных сообщений. Сам SObjectizer берет на себя задачи диспетчеризации сообщений и предоставление агентам рабочего контекста для обработки получаемых сообщений.

Проект живет на SourceForge, распространяется под трехпунктной BSD-лицензией.

Версию 5.5.5 можно взять либо из секции Files на SF, либо из Svn-репозитория, либо из зеркала на GitHub.

Если говорить кратко, то в версии 5.5.5 появилось следующее:

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

Так же подготовлены две новые части серии презентаций “Dive into SObjectizer-5.5”, более подробно рассказывающие о состояниях агентов и кооперациях агентов (все имеющиеся презентации собраны здесь).

Если интересны подробности, то сюда.

Отдельная благодарность Алексею Сырникову, как за помощь в подготовке этого релиза, так и за поддержку зеркала SObjectizer на GitHub-е.

★★★★★
Ответ на: комментарий от anonymous

пойми, эрланг это и есть библиотека акторов, написана на с

Боюсь, вы что-то путаете. Прежде всего Erlang — это динамически-типизированный язык программирования, со сборкой мусора и собственной VM. А уже эта VM написана на C (как и еще куча других VM).

Далее, Erlang — это OTP, без которой Erlang мало кому нужен. А OTP — это куча библиотек, написанных, как это не странно, на Erlang-е. В чем не трудно убедиться, если заглянуть в исходники. Вот, например, в составе OTP-17.5:

-------------------------------------------------------------------------------
Language                     files          blank        comment           code
-------------------------------------------------------------------------------
Erlang                        4305         284987         370027        1666320
XML                            990          32674           2288         368294
C                              540          45662          40499         293743
Bourne Shell                    96           9998           9994          85829
C/C++ Header                   288           8082          12054          53362
C++                             15            372            479          41583
make                           345           7963          11705          18089
XSD                             35            337            223          14209
Java                            97           2769           7535          10569

При этом Erlang, как язык, не имеет каких-либо нормальных инструментов для разработки абстракций. Там из структурированных типов данных всего-то list, record и, с недавних пор, map.

А производительность Erlang-ового кода такова, что вещи вроде подсчета контрольных сумм, нужно писать на C в виде NIF-ов.

детских проблем, которые есть у со5

Ануткать, с этого места поподробнее.

ты пишешь велосипед на с++11 (который не в каждой приличной конторе примут),

Это в каких приличных конторах не используют c++11 для новых проектов? И в каких приличных конторах не будут использовать c++11 (а затем и 14, и 17) в будущем?

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

Откуда дровишки?

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

Где, сударь? Вы бредите и у вас галюники.

eao197 ★★★★★ ()
Ответ на: комментарий от eao197

Это в каких приличных конторах не используют c++11 для новых проектов?

fcoo.dk :( для венды тут 2008 студия со всеми вытекающими. Тут в этом плане консерваторы. Есть куча серверов на 2000ой еще винде. И да. Мы тут такие - нифига не исключение.

anonymous ()
Ответ на: комментарий от anonymous

Мы тут такие - нифига не исключение

Ну так это же не может длится вечно. В конце-концов поддержка на уровне 2008-й студии или какого-нибудь GCC 4.0 будет обходиться все дороже и дороже.

eao197 ★★★★★ ()
Ответ на: комментарий от eao197

Прежде всего Erlang

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

А производительность Erlang-ового кода такова, что вещи вроде подсчета контрольных сумм, нужно писать на C в виде NIF-ов.

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

с этого места поподробнее.

вытесняющая многозадачность акторов.

Это в каких приличных конторах не используют c++11 для новых проектов?

не позорься. ты похож на школьника сейчас.

Откуда дровишки?

спеки спп - 1300 стр. спеки эрланга - 300 стр. конечно спп проще выучить, да.

Где, сударь?

в караганде. выше тебе уже разжевали.

anonymous ()
Ответ на: комментарий от eao197

Ну так это же не может длится вечно.

а тебя и спрашивать никто не будет. в моей конторе есть проект на ку3. думаешь его кто-то будет портировать на ку4 или 5?

anonymous ()
Ответ на: комментарий от anonymous

спеки спп - 1300 стр. спеки эрланга - 300 стр. конечно спп проще выучить, да.

Разве разговор был о выучить? Мне казалось был разговор об использовании. Берём специалистов на C++ и специалистов на erlang. С чего вы взяли, что проект, требующий в случае erlang'а много NIF, будет делать проще, чем на C++ с какой-то библиотекой факторов?

anonymous ()
Ответ на: комментарий от anonymous

Разве разговор был о выучить? Мне казалось был разговор об использовании. Берём специалистов на C++ и специалистов на erlang. С чего вы взяли, что проект, требующий в случае erlang'а много NIF, будет делать проще, чем на C++ с какой-то библиотекой факторов?

Если нужно очень много NIF'ов то, очевидно, лучше сразу С-ноду поднимать.

cyanide_regime ()
Ответ на: комментарий от anonymous

а ты его в со5 итерируя стл лист подсчитываешь, да. или акторами?

На so5 для подсчета контрольных сумм будет использоваться тот же самый C++, что и для остального проекта. В отличии от Erlang, где придется другой язык задействовать. Да еще и надеяться, что вставки на C в Erlang-е не начнут глючить, при изменении условий или переносе на другую платформу.

вытесняющая многозадачность акторов.

Еще раз для анонимных тимлидов: в C++ не нужно реализовывать шедулинг в библиотеке. В C++ используются родные потоки ОС и управляет этим шедулер ОС.

SO5 дает разработчику разнести своих агентов по рабочим потокам так, чтобы не страдать от того, что какой-то агент надолго уйдет в синхронный вызов OCCI/ODBC или чего-то подобного.

Собственно, здесь есть встречный вопрос: где именно окажется вытесняющая многозадачность Erlang-овского шедулера, если Erlang-овый процесс дернет NIF-ку (ведь без NIF-ки нет производительности в Erlang-е, как вы сами подтверждаете), а NIF-ка уйдет в OCCI/ODBC?

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

Это что, максимально доступный для вас уровень аргументации?

eao197 ★★★★★ ()
Ответ на: комментарий от anonymous

в моей конторе есть проект на ку3. думаешь его кто-то будет портировать на ку4 или 5?

Ну и кто для вас саппортит qt3? Во сколько это обходится?

eao197 ★★★★★ ()
Ответ на: комментарий от eao197

NIF-ку (ведь без NIF-ки нет производительности в Erlang-е, как вы сами подтверждаете), а NIF-ка уйдет в OCCI/ODBC?

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

cyanide_regime ()
Ответ на: комментарий от cyanide_regime

Такое делают драйвером, а не NIF'кой. NIF не должен надолго «залипать» - об этом сказано в документации.

Поскольку я, все-таки, не Erlang-ер, то для меня нет большой разницы между NIF, драйвером, портом и нодой.

eao197 ★★★★★ ()
Ответ на: комментарий от eao197

Поскольку я, все-таки, не Erlang-ер, то для меня нет большой разницы между NIF, драйвером, портом и нодой.

Native Implemented Function - в идеале - зависят только от своих аргументов, быстрые и не создают никаких активностей (вроде тредов и проч.)

Драйвер - штука, которая может иметь свою scheduler-friendly активность.

Порт - по сути программа, общающаяся с erlang-нодой через stdin/stdout.

Нода - полноценный узел, написанный на целиком на С.

cyanide_regime ()
Ответ на: комментарий от cyanide_regime

Это все понятно. Вопрос, опять же, возвращается к своему началу: если для производительности придется значительную часть кода писать на C (в виде NIF-ов, драйверов, портов и нод), то какого качества будет этот код и не окажется ли это все гораздо дороже в разработке/сопровождении, чем написание всей системы сразу на С++?

При этом вообще в стороне остается вопрос актуальности притягивания Erlang-а в том или ином случае. Например, если разрабатывается GUI-приложение масштаба GIMP-а, Photoshop-а или Lightroom-а. Насколько оправданным будет использование Erlang-а в приложении, где требуется и GUI, и высокая загрузка CPU, и выполнение I/O, но практически не нужна сеть и распределенность?

Или, например, если уже есть унаследованная кодовая база из сотен тысяч, если не миллионов строк C++ного кода. Что будет проще: частями переводить этот legacy на обновленную версию C++ с обновлением версий фреймворков (тот же Qt3 на Qt5, Boost.Lambda на C++11 lambda и т.д.) или писать рядом новую версию на Erlang, задействуя куски старого кода в NIF-ах/драйверах/портах? Ну и если переписывание legacy на новом языке все-таки выгодно, то почему должен рассматриваться именно Erlang, а не Java/Scala+Akka? Или Haskell+CloudHaskell? Или что-то еще?

eao197 ★★★★★ ()
Ответ на: комментарий от eao197

если для производительности придется значительную часть кода писать на C (в виде NIF-ов, драйверов, портов и нод), то какого качества будет этот код и не окажется ли это все гораздо дороже в разработке/сопровождении, чем написание всей системы сразу на С++?

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

При этом вообще в стороне остается вопрос актуальности притягивания Erlang-а в том или ином случае. Например, если разрабатывается GUI-приложение

Например, если разрабатывается GUI-приложение

GUI-приложение

Erlang

Ну ты понял. У нас хоть и есть wx, но удовольствие это сомнительное.

Или, например, если уже есть унаследованная кодовая база из сотен тысяч, если не миллионов строк C++ного кода. Что будет проще: частями переводить этот legacy на обновленную версию C++ с обновлением версий фреймворков (тот же Qt3 на Qt5, Boost.Lambda на C++11 lambda и т.д.) или писать рядом новую версию на Erlang, задействуя куски старого кода в NIF-ах/драйверах/портах?

Разве тут может быть готовый ответ? Зависит от состояния кодовой базы, вестимо. Может имеет смысл переписывать с нуля. А может и просто допиливать напильником, ведь все и так работает.

Ну и если переписывание legacy на новом языке все-таки выгодно, то почему должен рассматриваться именно Erlang, а не Java/Scala+Akka? Или Haskell+CloudHaskell? Или что-то еще?

NIF, драйвер, порт. Вот три магических слова. Если переписывать legacy с С\С++ то именно возможность легкой интеграции Erlang'a с этими языками решает. Но это на мой взгляд.

cyanide_regime ()
Ответ на: комментарий от eao197

По поводу Haskell'a: с ним, я так понимаю, не все так просто. Здорово, если в команде есть опытный хаскелист, но если его нет?

cyanide_regime ()
Ответ на: комментарий от eao197

FreeBSD и clang, а так же под Linux и GCC.

Надеюсь на Linux/Clang проблем нет?

vertexua ★★☆☆☆ ()
Ответ на: комментарий от vertexua

Надеюсь на Linux/Clang проблем нет?

Нет.

Под Windows Clang не проверяется, а под FreeBSD/Linux проблем нет.

eao197 ★★★★★ ()
Ответ на: комментарий от cyanide_regime

Здорово, если в команде есть опытный хаскелист, но если его нет?

Здорово, если в команде есть опытный Erlang-ист...
Здорово, если в команде есть опытный C-шник...
Здорово, если в команде есть опытный...

Если у вас есть опытная команда C++ников, выбор Erlang-а, на котором никто не программировал, не будет хорошим решением, даже не смотря на уверения LOR-овских экспертов.

Ровно как и наоборот.

eao197 ★★★★★ ()
Ответ на: комментарий от eao197

Еще раз для анонимных тимлидов: в C++ не нужно реализовывать шедулинг в библиотеке. В C++ используются родные потоки ОС и управляет этим шедулер ОС.

Насколько потоки ОС «тяжелее» эрланговских? Например по памяти.

migesok ()
Ответ на: комментарий от eao197

Если у вас есть опытная команда C++ников, выбор Erlang-а, на котором никто не программировал, не будет хорошим решением, даже не смотря на уверения LOR-овских экспертов.

Если выбирать между простым как топор Erlang'ом и Haskell'ом (будем считать что опытные программисты на С++ ни тот, ни другой не знают), то думаю, скорость обучения языку, развитость платформы и легкость интеграции с С\С++ явно указывает на первый.

cyanide_regime ()
Ответ на: комментарий от cyanide_regime

Разве тут может быть готовый ответ? Зависит от состояния кодовой базы, вестимо. Может имеет смысл переписывать с нуля. А может и просто допиливать напильником, ведь все и так работает.

Ну так в это все и упирается. Есть глобальный выбор — остаемся на C++ или идем куда-то еще?

Если остаемся, то возникает следующий выбор — нужно ли решать проблемы многопоточности в C++ном коде через mutex/semaphores и самодельные thread-safe message queue или же можно применить модель акторов и взять готовый инструмент для этого? А может пойти еще каким-то другим путем?

Если есть смысл пробовать модель акторов, то какой инструмент взять: написать свой или взять какой-то готовый?

Если брать какой-то готовый, то какой именно?

На всех этих уровнях нет какого-то одного универсального ответа, все будут определять конкретные условия. И если так случится, что при поиске ответов на вышеозначенные вопросы кто-то подойдет к последнему пункту, то окажется, что выбор невелик. Из живых OpenSource реализаций есть разве что CAF и SO5.

Как раз на эту тему и хотелось бы поговорить в анонсе инструмента для упрощения разработки на C++.

А не о том, что в абстрактных задачах, граничных условий которых никто не знает, Erlang/C будет круче, чем C++/SObjectizer.

eao197 ★★★★★ ()
Ответ на: комментарий от cyanide_regime

Если выбирать между простым как топор Erlang'ом и Haskell'ом

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

Аналогично и между Erlang и Haskell. Лишь одна сторона этого спора: динамика vs статика приведет к бесконечным разборкам.

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

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

eao197 ★★★★★ ()
Ответ на: комментарий от migesok

Насколько потоки ОС «тяжелее» эрланговских? Например по памяти.

Полагаю, что значительно. Там, где в Erlang-е без оглядки создается 10K процессов, в C++ нужно сильно подумать, чтобы решиться на такое.

Тем не менее, создать 100 или 500 потоков в нативном приложении можно без проблем, причем, если большая часть из них будет занята ожиданием на синхронных вызовах, то это не будет заметно сказываться на отзывчивости приложения.

Если же синхронных вызовов мало, а стоит задача, например, по-максимуму утилизировать ядра CPU, то смысла создавать множество тяжелых потоков ОС вообще нет.

Собственно, здесь можно уже начинать тему о том, почему программирование на акторах в C++ будет значительно отличаться от такового в Erlang-е.

eao197 ★★★★★ ()

Я пока не читал всю документацию, скажите пожалуйста как решается проблема с thread starvation если например какие-то актеры выполняют cpu intensive или blocking IO задачи, а каким-то другим актерам нужна высокая отзывчивость?

vertexua ★★☆☆☆ ()
Ответ на: комментарий от vertexua

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

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

Сейчас «из коробки» есть такие диспетчеры:

  • one_thread, все привязанные к диспетчеру агенты работают на одной общей нити;
  • active_obj, каждый агент получает свою собственную рабочую нить;
  • active_group, каждой отдельной группе агентов выделяется своя рабочая нить;
  • thread_pool, привязанные к диспетчеру агенты распределяются между нитями из пула;
  • adv_thread_pool, так же пул нитей на которых работают агенты, но если агент декларирует свои события как thread-safe, то несколько событий одного агента могут обрабатываться параллельно на соседних нитях пула.

За счет этого можно сделать, например, так:

  • выделить one_thread-диспетчер для агента, который будет работать с MQ-шным сервером по AMQP (т.е. подписываться/читать/публиковать);
  • выделить thread_pool-диспетчер для агентов, которые выполняют прикладную обработку полученных от MQ сообщений;
  • выделить active_obj-диспетчер для агентов, которые будут выполнять операции с СУБД;
  • выделить active_obj-диспетчер для агентов, который будут работать с подключенными к компьютеру устройствами (вроде HSM, SmartCard-ридерами, I/O-контроллерами и т.д.)

При этом программирование в агентах на SO5 не похоже на таковое в Erlang или CAF. Оно скорее напоминает SEDA-подход со стадийностью обработки прикладных задач. В SO5 под каждую стадию (I/O, DBMS, ext.device, etc) выделяется агент/группа агентов со своим диспетчером и своим рабочим контекстом. Агенты, которые занимаются только быстротечным диспатчингом запросов (т.е. получили сообщение, проанализировали куда оно идет, переслали, получили ответ, проанализировали, отправили дальше), собираются либо на единичных one_thread диспетчерах, либо в виде групп на active_group-диспетчерах, либо на одном-двух (adv_)thread_pool диспетчерах.

При этом важно отметить еще и то, что агенты и типы диспетчеров — это ортогональные друг другу понятия. Один и тот же агент, в зависимости от задачи, может быть привязан как к one_thread, так и к adv_thread_pool диспетчеру. В коде самого агента от этого ничего не изменится. Что так же сильно упрощает разработку софта с использованием SO5.

eao197 ★★★★★ ()
Ответ на: комментарий от vertexua

Я пока не читал всю документацию,

Для первого знакомства можно просмотреть слайды, которые собраны вот здесь. Так может быть быстрее, чем вычитывать более подробный материал в Wiki.

eao197 ★★★★★ ()
Ответ на: комментарий от eao197

Хм, а почему медленно так ходят сообщения? Смотрю слайды, а там 100540 и 100541 сообщений понг и пинг соответсвенно за секунду.

-module(pingpong).
-export([ping/0,pong/1]).

pong(N) ->
  receive
    {ping, From} -> From ! pong, pong(N + 1);
    {stop, From} -> From ! {stop, N}
  end.

ping() ->
  Pong = erlang:spawn(?MODULE, pong, [0]),
  F    = fun Ping() ->
          Pong ! {ping, self()},
          receive
            pong -> Ping();
            {stop, N} -> {ok, N}
          end end,
  erlang:send_after(1000, Pong, {stop, self()}),
  timer:tc(F).

На моем i5-3470 @ 3.2 GHz, 8GB RAM дает в среднем по 1200000 сообщений того и другого типа, в сумме ~2.4M.

cyanide_regime ()
Ответ на: комментарий от cyanide_regime

Вы один ноль пропустили. В сумме получается около 2M.

anonymous ()
Ответ на: комментарий от cyanide_regime

Хм, а почему медленно так ходят сообщения? Смотрю слайды, а там 100540 и 100541 сообщений понг и пинг соответсвенно за секунду.

Может в цифрах запутались? :)

Там числа такие: 1_005_040 и 1_005_041, т.е. ~2M сообщений на процессоре, который работает на меньшей тактовой частоте. Ну и под Windows.

Кроме того, SO5 на таких бенчмарках работает медленнее, чем тот же CAF, но это из-за того, что в SO5 используется pub/sub модель взаимодействия. Т.е. сообщение недостаточно просто поместить в очередь, есть некоторые накладные расходы на обслуживание подписок.

eao197 ★★★★★ ()
Ответ на: комментарий от eao197

Может в цифрах запутались? :)

Ага, я просто перепечатал криво. И имел в виду различие 2М vs 2.4M

cyanide_regime ()
Ответ на: комментарий от eao197

Кроме того, SO5 на таких бенчмарках работает медленнее, чем тот же CAF, но это из-за того, что в SO5 используется pub/sub модель взаимодействия. Т.е. сообщение недостаточно просто поместить в очередь, есть некоторые накладные расходы на обслуживание подписок.

Спасибо, все понятно. А erlang-style почтовые ящики есть? Т.е. тупо перекладывание сообщений из одного актора в другой?

cyanide_regime ()
Ответ на: комментарий от eao197

Поясню свой вопрос. Довольно часто сталкиваюсь с конструкциями вроде:

ALSA -> GSMEnc -> Buffering -> UDP и т.п.

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

cyanide_regime ()
Ответ на: комментарий от cyanide_regime

А erlang-style почтовые ящики есть? Т.е. тупо перекладывание сообщений из одного актора в другой?

Тут вот какое дело.

Есть два типа почтовых ящиков — Multi-producer/Multi-Consumer и Multi-Producer/Single-Consumer.

Первый, MPMC — это чистой воды pub/sub, при отсылке сообщения в него выполняется двойная обработка сообщения: первый раз при отсылке определяются получатели сообщения (блокировка в mbox-е), второй раз после извлечения из event-queue при поиске обработчика события (еще одна блокировка).

Второй, MPSC — очень похож на то, что есть в Erlang/CAF и, полагаю, в Akka. Т.е. сообщение напрямую кладется в event-queue. И после извлечения из event-queue идет поиск обработчика события (такая же блокировка, как в случае с MPMC).

MPSC почтовые ящики есть у каждого агента (этим они так же похожи на механизмы взаимодействия Erlang/CAF). Взаимодействие через MPSC работает где-то на 20% быстрее, чем через MPMC (иногда больше, иногда меньше).

В данном примере с ping-pong-ом как раз MPSC mbox-ы. Т.е. скорость максимальная на данный момент.

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

Есть мысль о том, как от этого избавиться, но тут будет нарушена совместимость в поведении SO5 в определенных условиях. И как это отразиться на работоспособности написанных на SO-5.5.* проектов пока не понятно полностью. Поэтому эта оптимизация пока не сделана, а отложена до версии 5.6.0.

Ну и еще один нюанс. В презентации приведены замеры для 5.5.3. За это время в версиях 5.5.4 и 5.5.5 были добавлены новые фичи, которые слегка замедлили функции send/deliver_message. Так что сейчас показатели должны быть еще чуть ниже. Но за счет добавления таких фич, как message_limits и delivery_filters.

По этому показателю SO5, полагаю, будет чуть помедленнее CAF и Erlang-а в тестах на простую пропускную способность маленьких сообщений.

eao197 ★★★★★ ()
Ответ на: комментарий от cyanide_regime

Есть ли для SO5 примеры создания подобных конструкций?

Возможно, я трактую ваш вопрос слишком широко. Поэтому уточню на всякий случай.

Если речь идет о том, что N агентов выстроены в одну простую цепочку, в которой i-й агент формирует сообщение и отсылает его строго одному (i+1)-му агенту, то это делается без проблем за счет MPSC-mbox-ов. Т.е. достаточно i-му агенту сообщить mbox следующего (i+1)-го mbox-а и все.

Другое дело, что здесь может встать проблема producer-consumer, при которой нужно будет заботиться о том, чтобы i-й агент не генерировал больше работы, чем способен выполнить (i+1)-й агент.

eao197 ★★★★★ ()
Ответ на: комментарий от eao197

Если речь идет о том, что N агентов выстроены в одну простую цепочку, в которой i-й агент формирует сообщение и отсылает его строго одному (i+1)-му агенту, то это делается без проблем за счет MPSC-mbox-ов. Т.е. достаточно i-му агенту сообщить mbox следующего (i+1)-го mbox-а и все.

Да, об этом. Я имел в виду «сахар» для таких конструкций, например (псевдокод), pipe<alsa_agent, alsa_frame>() >> pipe<gsmenc_agent, gsm_frame>() и т.д. Но раз все и так тривиально реализуется, то ладно.

cyanide_regime ()
Ответ на: комментарий от eao197

Просто, было бы удобно уметь без лишних правок втыкать в пайп новые акторы, не трогая все остальные. Удобно и при отладке и в целом. =)

cyanide_regime ()
Ответ на: комментарий от cyanide_regime

Просто, было бы удобно уметь без лишних правок втыкать в пайп новые акторы, не трогая все остальные. Удобно и при отладке и в целом. =)

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

Вот в вашей записи:

pipe<alsa_agent, alsa_frame>() >> pipe<gsmenc_agent, gsm_frame>()
alsa_frame — это тип сообщения, которое приходит на вход агенту alsa, а gsm_frame — это тип сообщения, которое приходит на вход агенту gsmenc_agent?

eao197 ★★★★★ ()
Ответ на: комментарий от cyanide_regime

alsa_agent создает alsa_frame, передает в gsmenc_agent, а тот выплевывает gsm_frame.

Есть у меня подозрение, что для такого рода задач с конвейерами можно сделать набор шаблонных агентов и шаблонных функций pipe, которые будут наружу выставлять что-то подобное. А внутри будут обычные mbox-ы и обычные send-ы.

eao197 ★★★★★ ()
Ответ на: комментарий от eao197

Есть у меня подозрение, что для такого рода задач с конвейерами можно сделать набор шаблонных агентов и шаблонных функций pipe, которые будут наружу выставлять что-то подобное. А внутри будут обычные mbox-ы и обычные send-ы.

Я и спрашиваю, сделал ли это кто-нибудь до меня, чтобы не делать двойной работы.)

cyanide_regime ()
Ответ на: комментарий от cyanide_regime

Я и спрашиваю, сделал ли это кто-нибудь до меня, чтобы не делать двойной работы.)

Нет, сам не делал и не слышал, чтобы кто-то делал.

eao197 ★★★★★ ()
Ответ на: комментарий от cyanide_regime

alsa_agent создает alsa_frame, передает в gsmenc_agent, а тот выплевывает gsm_frame.

Любопытную задачку вы подкинули, интересно мозги поразмять :) Только вот пока думается, что наиболее сложные вопросы здесь — это как представлять начальную (source) и конечную (sink) точку такого пайпа. У source же нет исходного сообщения, которое к нему на вход идет. А у sink-а нет исходящего сообщения. Соответственно, конструирование будет выглядеть как-то так:

src(alsa_agent) | pipe(gsmenc_agent) | pipe(buffered) | sink(udp_agent);
Все это напоминает популярный сейчас reactive programming.

Нет желание обсудить это дело в привате? Или можно прямо здесь продолжить, может кому-то из читателей будет интересно.

eao197 ★★★★★ ()
Ответ на: комментарий от eao197

мне интересно. Я тут прям щас смотрю презентахи по SO. Пока мало что понятно, что куда и зачем, да и задачу пока не придумал, но вдруг на мыслю наведешь.

anonymous ()
Вы не можете добавлять комментарии в эту тему. Тема перемещена в архив.