Обзор sobjectizer 5.5

Post on 15-Aug-2015

80 Views

Category:

Software

5 Downloads

Preview:

Click to see full reader

TRANSCRIPT

Обзор SObjectizer-5.5

SObjectizer Team, февраль 2015

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

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

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

Time.

SObjectizer Team, февраль 2015

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

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

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

SObjectizer Team, февраль 2015

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

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

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

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

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

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

SObjectizer Team, февраль 2015

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

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

SObjectizer Team, февраль 2015

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

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

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

SObjectizer Team, февраль 2015

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

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/

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

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

SObjectizer Team, февраль 2015

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

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

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

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

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

SObjectizer Team, февраль 2015

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

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

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

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

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

этой кухней.

SObjectizer Team, февраль 2015

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

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

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

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

SObjectizer Team, февраль 2015

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

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

SObjectizer Team, февраль 2015

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

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

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

SObjectizer Team, февраль 2015

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

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 ) ) {}};

Код примера (агент 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; }

Код примера (агент 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 ); }

Код примера (агент 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;};

Код примера (агент 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 ); } ); }

Код примера (агент 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;};

Код примера (агент 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 ) {}

Код примера (агент 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 ); }

Код примера (агент 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 ) ); }

Код примера (агент 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(); }};

Код примера (функция 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; }}

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

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

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

Сайт проекта: 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

top related