LINUX.ORG.RU

SObjectizer v.5.5.19

 , , , ,


1

6

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

Во-первых, добавлена возможность запускать SObjectizer в однопоточном режиме. Т.е. теперь можно написать приложение на акторах так, что все акторы и вся вспомогательная кухня самого SObjectizer-а будут работать на одной единственной рабочей нити. Это может пригодиться при написании простых приложений, в которых наличие акторов может быть выгодно (для упрощения логики), а вот создание нескольких рабочих потоков — это уже оверкилл. Например, если маленькая программка должна собирать какую-то информацию и время от времени публиковать ее через MQTT. Или, скажем, при написании своей хитрой версии traceroute. Вот маленькая демонстрация того, к чему все это может прийти в пределе: тривиальный http-сервер для асинхронной обработки запросов на базе SObjectizer и restinio.

Во-вторых, добавлена возможность отсылки мутабельных сообщений. Поскольку ноги у SO-5 растут из модели Publish/Subscribe, в которой взаимодействие идет в режиме 1:N, все сообщения в SO-5 изначально были иммутабельными. В большинстве случаев это упрощало жизнь, но мешало в тех ситуациях, когда нужно было, например, построить обработку данных в режиме конвейера: один агент модифицировал данные и передавал их следующему в конвейере, при этом взаимодействие в конвейере всегда идет в режиме 1:1. В итоге в версии 5.5.19 добавлена поддержка мутабельных сообщений с обеспечением гарантии того, что мутабельное сообщение будет доставлено не более чем одному получателю. Подробнее все это показано в новой презентации из серии «Dive into SObjectizer-5.5». Кстати говоря, данная фича появилась после общения в кулуарах на C++ Russua 2017.

Все изменения в 5.5.19 описаны здесь.

Загрузить новую версию можно либо в виде архива с SourceForge, либо из svn-репозитория проекта, либо из зеркала на GitHub.

Между релизами 5.5.18 и 5.5.19 прошло довольно много времени, хотя на то были объективные причины. Надеемся, что работа над следующей версией, 5.5.20, пойдет быстрее и мы сможем выкатить ее в конце лета 2017-го.

Для будущей версии 5.5.20 у нас есть несколько своих идей, но в этом плане мы полностью открыты и готовы выслушать любые замечания и предложения. Так что, если кто-нибудь расскажет, что он хотел бы видеть в SObjectizer или, напротив, чего бы не хотел, то мы постараемся учесть это в своей работе. Опыт реализации таких фич, как отказ от дополнительного пространства имен so_5::rt, приоритеты агентов, иерархические конечные автоматы и мутабельные сообщения показывает, что это более чем возможно.

ЗЫ. Старую тему с анонсами SO-5 решил не поднимать, т.к. было это уже слишком давно. Для, кто не в курсе, что такое SObjectizer — это один из немногих живых и развивающихся OpenSource кросс-платформенных фреймворков для C++, которые дают разработчику возможность использовать Actor Model (в случае с SO-5 сюда добавляются еще и Pub/Sub, и CSP).

★★★★★

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

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

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

Хотя относится это к виртуальным методам внутри шаблонных классов.

а можно пример строчки с этим. У меня кажется такое же было и я починил.

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

Пример строки кода или пример сообщения об ошибке?

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

а можно пример строчки с этим. У меня кажется такое же было и я починил.

Вот пример того, как ругается GCC 7.1:

Compiling test/so_5/mchain/simple/main.cpp ...
In file included from ./so_5/rt/h/rt.hpp:12:0,
                 from ./so_5/all.hpp:15,
                 from test/so_5/mchain/simple/main.cpp:5:
./so_5/rt/h/message.hpp:907:3: error: 'void so_5::msg_service_request_t<RESULT, PARAM>::set_exception(std::__exception_ptr::exception_ptr) [with RESULT = void; PARAM = main()::<lambda()>::hello]' declared 'static' but never defined [-Werror=unused-function]
   set_exception( std::exception_ptr what ) override
   ^~~~~~~~~~~~~
./so_5/rt/h/message.hpp:929:3: error: 'void so_5::msg_service_request_t<RESULT, PARAM>::so5_change_mutability(so_5::message_mutability_t) [with RESULT = void; PARAM = main()::<lambda()>::hello]' declared 'static' but never defined [-Werror=unused-function]
   so5_change_mutability( message_mutability_t v ) override
   ^~~~~~~~~~~~~~~~~~~~~

Соответственно, вот строка 907. И вот строка 929. А вот где эти методы первоначально определяются: set_exception, so5_change_mutability

Причем GCC ругался на эти места не всегда, а где-то с 6-ой версии, если не ошибаюсь.

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

Сделал тег 5.5.19.1, в котором код, который собирается gcc и clang с ключами -Wpedantic и -Werror. Для gcc 6.* и 7.* может потребоваться добавить ключ -Wno-unused-function, иначе в одном из мест у gcc сносит крышу и он ругается на то, на что ругаться не должен.

Взять 5.5.19.1 можно либо из svn, либо с github-а, либо в виде архива с SourceForge.

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

у меня UTR. вот такая гцц

gcc (Ubuntu 6.2.0-5ubuntu12) 6.2.0 20161005

C -Werror не собирается из-за лишних запятых после namespace'ов, например тут work_thread_activity.hpp:48

Все остальное без варнингов.

anonymous ()

concurrency

Оно на корутинах/грин тредах работает?

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

Попробуйте 5.5.19.1, там уже этих точек с запятой быть не должно.

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

Короутины (пока?) не поддерживаются. Используются обычные треды.

eao197 ★★★★★ ()

На случай, если кто-то захочет высказать свое мнение о том, чего ему лично не хватает в SObjectizer: http://eao197.blogspot.com/2017/06/progc-erlang-style-sobjectizer.html

Ну или если хотелось бы чего-то, что уже есть, но сделанного по-другому, то нам бы так же было бы интересно выслушать стороннее мнение. Есть далеко не нулевые шансы, что мы прислушаемся ;)

eao197 ★★★★★ ()

Мы выпустили первую версию своего нового проекта поверх SObjectizer — so_5_extra версии 1.0.0.

В этой версии в so_5_extra доступны:

  • so_5::extra::env_infrastructures::asio::simple_not_mtsafe — реализация однопоточной инфраструктуры SObjectizer-а на базе Asio. Т.е. с использованием этой инфраструктуры и Asio, и SObjectizer смогут работать на одной и той же рабочей нити;
  • so_5::extra::mboxes::round_robin — специальный mbox, который доставляет сообщения поочередно каждому из N агентов, подписанных на это сообщение;
  • so_5::extra::shutdowner — небольшой инструмент для упрощения операции завершения работы в больших приложениях.</li>

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

Документацию по проекту можно найти в Wiki. Если из документации чего-то не понятно или что-то в ней не описано, то не сочтите за труд, дайте нам знать. Улучшим, расширим и углубим :)

Проект header-only. Если захочется собрать тесты и примеры самостоятельно, то придется воспользоваться Ruby и Mxx_ru. Зависимости так же подтягиваются через MxxRu::externals. Но в секции Files есть архивы с именами вида so_5_extra-1.0.0-full.tar.xz, в которых уже все зависимости присутствуют. Поэтому можно брать *-full.tar.xz архив, распаковывать, прописывать в INCLUDE путь к so_5_extra-1.0.0/dev и пробовать.

Работоспособность проверялась под Linux-ом (gcc 5.4 и 7.1, clang 3.7 и 4.8) и Windows (gcc 5.2-7.1, VC++ 14.0 и 15.0). На всякий случай выставлять -Werror при работе с so_5_extra не советуем, т.к. и gcc, и clang очень сильно ругаются на потроха Asio.

В планах у нас добавление еще нескольких фич в so_5_extra. Следующие версии будут выходить по мере добавления новых фич. В том числе в планах и simple_mtsafe-инфраструктура для Asio, но приоритет у этой задачи не самый высокий. Если кому-то нужна thread-safe реализация Asio-инфраструктуры для SO-5, то дайте знать. Постараемся повысить приоритет.

Обращаем внимание, что so_5_extra распространяется под двойной лицензией: GNU Affero GPL для OpenSource применения, и коммерческая лицензия для использования в закрытых проектах. Если кому-то интересна коммерческая лицензия, то пишите на info at stiffstream dot com, там цена вопроса порядка $40 за одного разработчика в год.

Попутно мы сделали SObjectizer-5.5.19.2, в который вошло несколько фич, необходимых для реализации so_5_extra. Дистрибутивы SObjectizer лежат там же, где и обычно.

eao197 ★★★★★ ()

Извиняюсь за ссылку на Хабр, но мы сделали большую статью, в которой подробно рассматривается намного более сложный пример, чем абстрактные и бесполезные на практике ping-pong-и (коими принято меряться в разговорах про акторные фреймворки): Имитируем управление устройствами с помощью акторов

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

Как насчёт минусов использования модели акторов?

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

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

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

Как насчёт минусов использования модели акторов?

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

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

Это уж у кого как... :)

Может быть и так, что наверху будет какая-нибудь dataflow-модель (например, в виде модных нынче reactive streams), а акторы будут на низком уровне, в качестве базы для реализации dataflow-юнитов.

Как боротся со сложностью при большом количестве акторов?

Сильно зависит от того, что вы называете «сложностью при большом количестве акторов».

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

1. Довольно-таки сложнопредсказуемое поведение всего приложения. Скажем, может возникнуть ситуация, когда приложение грузит CPU под 100%, активно потребляет память, но при этом какой-то полезной работы от него не видно. И длится все это несколько десятков секунд, после чего потребление CPU опускается до приемлимого уровня, почти вся память освобождается и работа начинает идти обычным образом. При разбирательстве оказывается, что какая-то изрядная часть акторов в один и тот же момент начала делать одно и то же. Например, у 10K акторов сработали тайм-ауты на ожидание ответов от сторонней системы, которая сейчас стала отвечать на запросы слишком долго. И вот эта самая обработка тайм-аутов, случившаяся у 10K акторов одновременно, и выжрала все имеющися ресурсы. При этом каждый актор работает правильно и делает то, что от него требуется. Но вот поведение всего приложения в целом оказывается неожиданным.

2. Приложение с большим количеством акторов, каждый из которых содержит в себе какую-то часть важной информации, сложнее мониторить. Ну, например, акторы выполняют свои действия или обращаются к сторонним сервисам и засекают время выполнения этих действий. Получается, что какой-то конкретный актор знает, что ему потребовалось, к примеру, 12.5ms. Но акторов 100500 и как отобразить в каком-нибудь Zabbix-е «среднюю температуру по больнице»?

Как раз использование приемов из SEDA-подхода помогает бороться с этими проблемами. Но у нас была возможность перейти от акторов-операций (которые всю операцию выполняют сами) к акторам-стадиям (которые выполняют только одну часть операций но для большого количества операций). В каких-то областях это вряд ли возможно. Скажем, в статье была ссылка на Orleans, который использовался в Halo 4 и Halo 5. Там, если не ошибаюсь, каждый пользователь игры представлялся актором. Тут уж ничего не поделать, в приложении будет 100500 акторов и каждый будет вести себя независимо от других.

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

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

eao197 ★★★★★ ()

Мы попытались привести пример того, как SObjectizer упрощает разработку многопоточных программ даже без использования агентов, только за счет применения mchain-ов: Многопоточность в C++ и SObjectizer с CSP-шными каналами, но совсем без акторов…

Надеюсь, кому-нибудь будет интересно.

eao197 ★★★★★ ()

Очередные обновления наших проектов.

Официальный анонс на странице проекта

В so_5_extra добавились такие штуки как:

- однопоточная реализация SObjectizer на базе Asio, которая при этом является еще и thread-safe. Предназначена для случаев, например, когда нужно иметь свободный основной поток для GUI и отдельный рабочий поток, на котором будет совместно работать и SObjectizer, и Asio. И чтобы из главного потока можно было управлять SObjectizer-ом (создавать/удалять кооперации, отсылать сообщения, создавать mchain-ы и т.д.);

- диспетчер asio_thread_pool. Этот диспетчер создает пул рабочих потоков, на каждом из которых запускает io_service::run(). При этом диспетчеризация событий для агентов, которые привязаны к данному диспетчеру происходит через asio::post. Это позволяет привязанным к asio_thread_pool диспетчеру агентам выполнять IO-операции там же, где работает сам Asio-шный io_service.

Попутно мы обновили SO-5, но там вообще ничего не добавилось. Просто устранены предупреждения, которые стал выдавать clang-5.0.0. Что должно помочь тем, кто у себя компилирует SObjectizer clang-ом с высокими уровнями предупреждений.

--- Попутно открывается возможность начать работу над следующей версией SO-5. Точного списка фич для версии 5.5.20 пока нет, будет выбрано несколько пунктов из этого wish-list-а. Если у кого-то есть пожелания о том, что хотелось бы видеть в SObjectizer-е, можно высказать их, мы постараемся их учесть.

eao197 ★★★★★ ()

Очередное обновление SO-5.5.19: версия 5.5.19.5

На этот раз добавили в SO-5 проверку наличия подписок для агента. Оказалось, что бывают сценарии, где это востребовано. Заодно пофиксили формат некоторых методов so_drop_subscription, которые не менялись очень давно и не поддерживали новый формат event-handler-ов. В общем, изменения небольшие, но полезные.

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

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

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

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

Можно вот так:

struct service_result {...};
struct service_request {...};

class service_provider : public so_5::agent_t {
public:
  ...
  virtual void so_define_agent() override {
    // Make subscription to 'service_request'.
    so_subscribe_self().event(&service_provider::on_request);
    ...
  }
  ...
private:
  service_result on_request(mhood_t<service_request> cmd) {
    ... // Some processing.
    return {...};
  }
  ...
};
...
const so_5::mbox_t provider_mbox = ...;

auto f = so_5::request_future<service_result, service_request>(provider_mbox, ...); // std::future is returned.
...
service_result res = f.get();

Причем это будет работать даже если в качестве service_result будет указан void.

Подробнее здесь.

eao197 ★★★★★ ()

В следующем году мы планируем заняться версией 5.6, в которой будет нарушена совместимость с текущей веткой 5.5. Сделано это будет как для того, чтобы устранить выявленные за время эксплуатации SO-5 косяки, так и для того, чтобы сделать вещи, которые сейчас не представляется возможным внедрить в 5.5 без нарушения совместимости.

Первые идеи по поводу SO-5.6 можно посмотреть здесь. Соответственно, конструктивные соображения/замечания/предложения приветствуются и будут обязательно приняты к сведению. А может быть даже и реализованы :)

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

А не сомнительно ли ломать совместимость, не меняя мажорную версию?

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

У нас старший номер в версии меняется при полной переделке. Т.е. SO-4 и SO-5 не совместимы в принципе. Несовместимы настолько, что их можно совместно использовать в одном большом проекте, даже в одном .cpp-файле.

Второй номер в версии меняется, если появляются несовместимости, которые требуют только частичного изменения исходников. Например, в SO-5.5 сейчас метод abstract_message_mbox_t::do_deliver_message объявлен как const, в версии SO-5.6 он будет уже без const. Соответственно, все, кто имел своих наследников abstract_message_mbox_t, должны будут внести правки в свой код при переходе на SO-5.6. Но это небольшие и непринципиальные правки. При этом SO-5.5 и SO-5.6 в рамках одного проекта использовать просто так не получится (тем более в рамках одного .cpp-файла).

Изменение третьего (и четвертого) номера в версии говорит о том, что можно тупо взять SO-5.5.20 вместо 5.5.19, перекомпилироваться и все.

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

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

Virtuos86 ★★★★★ ()

SObjectizer-5.5.20 + so_5_extra-1.0.3

SObjectizer обновился до версии 5.5.20. Изменений в нем немного. Пожалуй, самое важное — это обновленная и улучшенная поддержка CMake. Полный список изменений можно увидеть здесь.

Загрузить новую версию можно либо в виде архива с SourceForge, либо из svn-репозитория проекта, либо из зеркала на GitHub.

Уже пару месяцев SObjectizer доступен через систему управления зависимостями vcpkg. Так что сейчас последнюю версию SO-5 можно установить себе посредством команды vcpkg install sobjectizer.

so_5_extra обновился до версии 1.0.3, в которой был добавлен еще один тип mbox-а: retained_msg mbox.

Взять so_5_extra можно либо в виде архива с SourceForge, либо из svn-репозитория.

Так же кого-то может заинтересовать свежая статья на Хабре, рассказывающая о такой важной штуке SObjectizer-а, как концепция mbox-ов.

eao197 ★★★★★ ()

Мы обновили SObjectizer до версии 5.5.21, а so_5_extra до версии 1.0.4.

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

Ну, например, пусть мы делаем агента распределяющего обработку запросов по нескольким обработчикам запросов. Этот агент получает сообщение request_data, определяет mbox, в который нужно переслать сообщение, а затем дождаться получение из этого mbox-а либо сообщения request_successed, либо сообщения request_failed. Так же должен учитываться тайм-аут на обработку запроса. Посредством асинхронных операций это может быть реализовано вот так:

class request_manager : public so_5::agent_t {
   struct request_timed_out {
      user_id user_;
      request_id id_;
   };
   ...
   void on_successful_result(mhood_t<request_successed> cmd) {...}
   void on_failed_result(mhood_t<request_failed> cmd) {...}
   void on_timeout(mhood_t<request_timed_out> cmd) {...}
   ...
   void on_new_request(mhood_t<request_data> cmd) {
      // Определяем, кто будет обрабатывать запрос.
      const auto processor_mbox = detect_processor_for_req(*cmd);

      // Подготавливаем асинхронную обработку запроса.
      so_5::extra::async_op::time_limited::make<request_timed_out>(*this)
         .completed_on(processor_mbox, so_default_state(),
            &request_manager::on_successful_result)
         .completed_on(processor_mbox, so_default_state(),
            &request_manager::on_failed_result)
         .timeout_handler(so_default_state(),
            &request_manager::on_timeout)
         .activate(5s, cmd->user_, cmd->id_);

      // Передаем запрос конкретному исполнителю.
      so_5::send(processor_mbox, cmd);
   }
   ...
};

Для того, чтобы сделать async_op в so_5_extra пришлось добавить в SO-5.5 такую штуку, как deadletter handler. Можно зарегистрировать deadletter handler для пары (message_type, mbox) и deadletter handler будет вызван, если у агента в его текущем состоянии нет обработчика для такой пары и типа сообщения и почтового ящика. Что позволяет делать обработчики сообщений «по умолчанию».

Подробнее о релизе можно прочитать здесь.

Взять дистрибутив новой версии SObjectizer-а можно из раздела Files на SourceForge. Документация по изменениям в версии 5.5.21 доступна здесь. Так же можно воспользоваться зеркалом на github. Пользователи vcpkg могут установить последнюю версию SObjectizer через vcpkg install sobjectizer.

Дистрибутив новой версии so_5_extra можно взять из раздела Files на SourceForge. Документация по изменениям в версии 1.0.4 доступна здесь.

eao197 ★★★★★ ()

Если кому-то интересно наблюдать за развитием SObjectizer-а и/или хочется повлиять на то, что и как добавляется в SObjectizer, то вот подходящий случай:

Как лучше добавить детализацию активности агентов в SObjectizer?

Действительно нужен свежий и заинтересованный взгляд со стороны.

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

Странно, что код в листингах код отображается пропорциональным Ш, а не моноширинным.

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

Да ХЗ, уже лет 8 или 9 так код в примерах в блоге оформляется, пока никто не жаловался.

eao197 ★★★★★ ()

На случай, если кому-то интересно и/или кто-то захочет высказать свое мнение. Статья на Хабре (прастити) с описанием того, как мы хотим расширить механизм msg_tracing в разрабатываемой сейчас версии 5.5.22: Когда акторный фреймворк превращается в «черный ящик» и что мы можем с этим сделать?

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

как мы хотим расширить механизм msg_tracing в разрабатываемой сейчас версии 5.5.22

Для интересующихся. Свежий, можно сказать, с пылу, с жару, пример того, как msg_tracing-фильтры упрощают отладку SObjectizer-овских приложений: тыц.

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