28
Обзор SObjectizer-5.5 SObjectizer Team, февраль 2015

Обзор SObjectizer 5.5

Embed Size (px)

Citation preview

Page 1: Обзор SObjectizer 5.5

Обзор SObjectizer-5.5

SObjectizer Team, февраль 2015

Page 2: Обзор SObjectizer 5.5

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

В зону ответственности SObjectizer входит:● диспетчеризация сообщений внутри одного процесса;● предоставление рабочего контекста для обработки

сообщений;● тонкая настройка параметров работы SObjectizer Run-

Time.

SObjectizer Team, февраль 2015

Page 3: Обзор SObjectizer 5.5

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

Приложение может быть целиком построено на базе SObjectizer.

Или же SObjectizer может быть использован лишь как фрагмент приложения, написанного на Qt, wxWidgets, ACE, Boost и т.д.

SObjectizer Team, февраль 2015

Page 4: Обзор SObjectizer 5.5

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

Влияние на SObjectizer оказала, в том числе, и модель акторов*. Хотя разработка SObjectizer началась задолго до того, как эта модель получила широкую известность.

SObjectizer Team, февраль 2015* http://en.wikipedia.org/wiki/Actor_model

Page 5: Обзор SObjectizer 5.5

Основные идеи и принципы работы SObjectizer были сформулированы в середине 1990-х годов, при разработке проекта SCADA Objectizer в Гомельском КБ Системного Программирования (1996-2000гг).

В 2002-м идеи SCADA Objectizer были заново реализованы в новом проекте SObjectizer-4.

В 2010-м развитие SObjectizer-4 завершилось и началась разработка SObjectizer-5.

SObjectizer Team, февраль 2015

Page 6: Обзор SObjectizer 5.5

В течении долгого времени SObjectizer был внутренним продуктом компании “Интервэйл”.

Он использовался при разработке систем:● передачи SMS/USSD трафика;● обслуживания финансовых транзакций;● мониторинга параметров ПО.

SObjectizer Team, февраль 2015

Page 7: Обзор SObjectizer 5.5

В 2006-м году SObjectizer был опубликован на SourceForge как OpenSource проект под 3-х секционной BSD-лицензией.

С 2013-го года разработка SObjectizer ведется полностью на SourceForge.

На данный момент SObjectizer ‒ это самостоятельный проект, независимый от компании “Интервэйл”.

SObjectizer Team, февраль 2015

Page 8: Обзор SObjectizer 5.5

SObjectizer-5 разрабатывается на C++11 и опирается на возможности стандартной библиотеки C++11.

При разработке SObjectizer-5 используются компиляторы Visual C++ 12.0, GCC 4.9 и clang 3.5 на платформах Windows 7/8/8.1 и Linux.

Поддержка других платформ возможна, если у разработчиков SObjectizer появится к ним доступ.

SObjectizer Team, февраль 2015

Page 9: Обзор SObjectizer 5.5

C мая 2013-го года состоялось 12 релизов SObjectizer-5.

Последняя стабильная версия ‒ 5.5.3, опубликована в февреле 2015.

Версия 5.5.3 ‒ это ~12 KLOC кода самого SObjectizer.Плюс ~12.5 KLOC кода тестов.Плюс ~5 KLOC кода примеров.

Плюс документация* по ядру SObjectizer и примерам.Плюс статьи и презентации**.

SObjectizer Team, февраль 2015*http://sourceforge.net/p/sobjectizer/wiki/Basics/**http://sourceforge.net/p/sobjectizer/wiki/Articles/

Page 10: Обзор SObjectizer 5.5

При использовании SObjectizer-5.5 программист отвечает за определение сообщений/сигналов и реализацию агентов для их обработки.

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

SObjectizer Team, февраль 2015

Page 11: Обзор SObjectizer 5.5

SObjectizer предоставляет набор готовых диспетчеров:● one_thread. Запускает всех агентов на одной общей рабочей нити;● active_obj. Предоставляет каждому агенту отдельную нить в

единоличное пользование;● active_group. Предоставляет отдельную нить в единоличное

пользование группе объектов;● thread_pool. Выделяет агентам нити из пула рабочих нитей. Агенты

могут мигрировать с одной рабочей нити на другую. Но агент не может работать на двух рабочих нитях одновременно;

● adv_thread_pool. Выделяет агентам нити из пула рабочих нитей. Агенты могут и мигрировать с одной рабочей нити на другую, и работать сразу на нескольких (при условии, что их обработчики событий объявлены thread safe).

SObjectizer Team, февраль 2015

Page 12: Обзор SObjectizer 5.5

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

● один one_thread диспетчер для агента-клиента AMQP;● один thread_pool диспетчер для обработки прочитанных из AMQP-

очередей запросов;● один active_obj диспетчер для агентов, выполняющих работу с

СУБД;● еще один active_obj диспетчер для агентов, работающих с

подключенными к компьютеру HSM-ами;● и еще один thread_pool диспетчер для агентов, следящих за всей

этой кухней.

SObjectizer Team, февраль 2015

Page 13: Обзор SObjectizer 5.5

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

Агент ‒ это легковесная сущность.

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

Количество агентов ограничивается доступным объемом оперативной памяти и здравым смыслом разработчика.

SObjectizer Team, февраль 2015

Page 14: Обзор SObjectizer 5.5

Вот пример кода на SObjectizer, демонстрирующий почти все ключевые особенности SObjectizer-5.5:

● состояния агента,● сообщения и сигналы,● родительские и дочерние кооперации,● диспетчеры,● отложенные сообщения и т.д.

SObjectizer Team, февраль 2015

Page 15: Обзор SObjectizer 5.5

Родительский агент создает пару агентов pinger и ponger, которые в течении одной секунды обмениваются друг с другом сигналами ping/pong.

По истечении секунды родительский агент дерегистрирует pinger-а и ponger-а.

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

SObjectizer Team, февраль 2015

Page 16: Обзор SObjectizer 5.5

Код примера (определение сигналов и сообщений):

SObjectizer Team, февраль 2015

#include <iostream>#include <string>

// Main SObjectizer header file.#include <so_5/all.hpp>

// Ping signal.// Signal is a special type of message which has no actual data.// Sending of signals is like sending only atoms in Erlang.struct ping : public so_5::rt::signal_t {};

// Pong signal.struct pong : public so_5::rt::signal_t {};

// Message with result of pinger/ponger run.// Unlike signal message must have actual data.struct run_result : public so_5::rt::message_t { std::string m_result;

// Messages usually have a constructor for // simplification of message construction. run_result( std::string result ) : m_result( std::move( result ) ) {}};

Page 17: Обзор SObjectizer 5.5

Код примера (агент pinger, начало):

SObjectizer Team, февраль 2015

// Pinger agent.class pinger : public so_5::rt::agent_t {public : pinger( // SObjectizer Environment to work within. so_5::rt::environment_t & env, // Parent's mbox for result sending. const so_5::rt::mbox_t & parent ) : so_5::rt::agent_t( env ) , m_parent( parent ) {}

// Ponger mbox will be available only after // creation of pinger/ponger pair. // This method allows to set it up later. void set_ponger_mbox( const so_5::rt::mbox_t & mbox ) { m_ponger = mbox; }

Page 18: Обзор SObjectizer 5.5

Код примера (агент pinger, продолжение):

SObjectizer Team, февраль 2015

// This method is automatically called by SObjectizer // during agent's registration procedure. virtual void so_define_agent() override { // Subscription for only one signal. so_default_state().event< pong >( [this]{ ++m_pongs; so_5::send< ping >( m_ponger ); } ); }

// This method is automatically called by SObjectizer // just after successful registration. // Pinger uses this method to initiate message exchange. virtual void so_evt_start() override { // Sending signal by corresponding function. so_5::send< ping >( m_ponger ); }

Page 19: Обзор SObjectizer 5.5

Код примера (агент pinger, окончание):

SObjectizer Team, февраль 2015

// This method is automatically called by SObjectizer // just after successful agent's deregistration. virtual void so_evt_finish() override { // Sending result message by corresponding function. so_5::send< run_result >( // Receiver of the message. m_parent, // This string will be forwarded to run_result's constructor. "pongs: " + std::to_string( m_pongs ) ); }

private : const so_5::rt::mbox_t m_parent; so_5::rt::mbox_t m_ponger; unsigned int m_pongs = 0;};

Page 20: Обзор SObjectizer 5.5

Код примера (агент pоnger, начало):

SObjectizer Team, февраль 2015

// Ponger agent is very similar to pinger.// But it hasn't so_evt_start method because it will// wait the first ping signal from the pinger.class ponger : public so_5::rt::agent_t {public : ponger( so_5::rt::environment_t & env, const so_5::rt::mbox_t & parent ) : so_5::rt::agent_t( env ) , m_parent( parent ) {}

void set_pinger_mbox( const so_5::rt::mbox_t & mbox ) { m_pinger = mbox; }

virtual void so_define_agent() override { so_default_state().event< ping >( [this]{ ++m_pings; so_5::send< pong >( m_pinger ); } ); }

Page 21: Обзор SObjectizer 5.5

Код примера (агент pоnger, окончание):

SObjectizer Team, февраль 2015

virtual void so_evt_finish() override { so_5::send< run_result >( m_parent, "pings: " + std::to_string( m_pings ) ); }

private : const so_5::rt::mbox_t m_parent; so_5::rt::mbox_t m_pinger; unsigned int m_pings = 0;};

Page 22: Обзор SObjectizer 5.5

Код примера (агент parent, начало):

SObjectizer Team, февраль 2015

// Parent agent.// Creates pair of pinger/ponger agents,// then limits their working time,// then handles their run results.class parent : public so_5::rt::agent_t {private : // Time limit signal. struct stop : public so_5::rt::signal_t {};

// Additional state for the agent. // This state means that the first result from children agents // has been received and that the parent expects the last one. const so_5::rt::state_t st_first_result_got = so_make_state();

// Result's accumulator. std::string m_results;

public : parent( so_5::rt::environment_t & env ) : so_5::rt::agent_t( env ) {}

Page 23: Обзор SObjectizer 5.5

Код примера (агент parent, продолжение-1):

SObjectizer Team, февраль 2015

virtual void so_define_agent() override { // Arrival of time limit signal means that // child cooperation must be deregistered. so_default_state().event< stop >( [this] { so_environment().deregister_coop( // Name of cooperation for deregistration. "pinger_ponger", // The reason of deregistration, // this value means that deregistration is caused // by application logic. so_5::rt::dereg_reason::normal ); } );

// NOTE: type of message is automatically deduced from // event handlers signatures.

// The first result will be received in default state. so_default_state().event( &parent::evt_first_result ); // But the second one will be received in the next state. st_first_result_got.event( &parent::evt_second_result ); }

Page 24: Обзор SObjectizer 5.5

Код примера (агент parent, продолжение-2):

SObjectizer Team, февраль 2015

virtual void so_evt_start() { // Child cooperation will use active_obj dispatcher. So pinger and ponger // will work on the different working threads. so_environment().add_dispatcher_if_not_exists( "active_obj", &so_5::disp::active_obj::create_disp );

// Creation of child cooperation with pinger and ponger. auto coop = so_5::rt::create_child_coop(*this, "pinger_ponger", // active_obj dispatcher will be used as a primary dispatcher for that cooperation. so_5::disp::active_obj::create_disp_binder("active_obj") );

// Filling the child cooperation. auto a_pinger = coop->add_agent( new pinger( so_environment(), so_direct_mbox() ) ); auto a_ponger = coop->add_agent( new ponger( so_environment(), so_direct_mbox() ) ); a_pinger->set_ponger_mbox( a_ponger->so_direct_mbox() ); a_ponger->set_pinger_mbox( a_pinger->so_direct_mbox() );

// Cooperation registration. so_environment().register_coop( std::move( coop ) ); // Limit the pinger/ponger exchange time. so_5::send_delayed_to_agent< stop >( *this, std::chrono::seconds( 1 ) ); }

Page 25: Обзор SObjectizer 5.5

Код примера (агент parent, окончание):

SObjectizer Team, февраль 2015

private : // Event handler for the first result. void evt_first_result( const run_result & evt ) { m_results = evt.m_result + "; ";

// State of the agent must be changed. this >>= st_first_result_got; }

// Event handler for the next (and last) result. void evt_second_result( const run_result & evt ) { m_results += evt.m_result;

// Show the results and finish work. std::cout << m_results << std::endl;

// This is deregistration of the last live cooperation. // SO Environment will finish its work. so_deregister_agent_coop_normally(); }};

Page 26: Обзор SObjectizer 5.5

Код примера (функция main):

SObjectizer Team, февраль 2015

int main() { try { // Create SO Environment objects and run SO Run-Time inside it. so_5::launch( // SO Environment initialization routine. []( so_5::rt::environment_t & env ) { // We must have the cooperation with just one // agent inside it. env.register_agent_as_coop( // The name for the cooperation will be generated // automatically by SO Environment. so_5::autoname, // The single agent in the cooperation. new parent( env ) ); } ); } catch( const std::exception & x ) { std::cerr << "Exception: " << x.what() << std::endl; }}

Page 27: Обзор SObjectizer 5.5

Результат работы:

pongs: 1005040; pings: 1005041

Т.е. порядка 2M сообщений в секунду при обмене единичными сообщениями между двумя нитями (pinger и ponger работают на разных нитях).

Core i7 2.4GHz, 8GiB RAM, Win8.1 64-bit,Visual C++ 2013 64-bit

SObjectizer Team, февраль 2015

Page 28: Обзор SObjectizer 5.5

Дополнительная информация:

Сайт проекта: http://sourceforge.net/projects/sobjectizer

Документация: http://sourceforge.net/p/sobjectizer/wiki/

Форум: http://sourceforge.net/p/sobjectizer/discussion/

Google-группа: https://groups.google.com/forum/#!forum/sobjectizer