SlideShare a Scribd company logo
1 of 73
Download to read offline
Модель Акторов и C++:
что, зачем и как?
Евгений Охотников
О чем пойдет речь?
Многопоточность и parallel concurrent computing.
Модель Акторов в двух-трех-четырех-...-двенадцати слайдах.
Сегодняшние иконы "Модели Акторов". Все две штуки.
А как же C++ (пока его еще не закопали)?
NIH*-синдром или что есть готового для C++?
2* NIH - Not Invented Here
Многопоточность – это...
инструмент, который активно применяется в двух очень разных областях:
● parallel computing (одновременно выполняются одинаковые операции
над разными наборами однотипных данных);
● concurrent computing (одновременно выполняются совсем разные
операции, возможно, над совершенно разными данными).
Concurrent computing может быть и без многопоточности. Но на базе
многопоточности concurrent computing доставляет больше всего...
3
Далее только о многопоточности...
...применительно к concurrent computing.
Именно здесь Модель Акторов оказывается очень удобной.
А для parallel computing используются другие подходы и другие
инструменты...
4
Итак, многопоточность – это сложно
Таки да, это сложно.
Даже имея 20 лет опыта.
Но почему?
5
Изменяемое разделяемое состояние
Именно изменяемое разделяемое состояние является одним из главных
факторов сложности в многопоточном программировании.
6
Как упростить себе жизнь?
7
Убрать разделяемое состояние
Ничего не разделяем. Ни за что не боремся.
Пусть каждый поток владеет своими собственными данными. И никто кроме
потока-владельца не имеет к этим данным доступа.
Принцип shared nothing* (широко известен в узких кругах).
8* https://en.wikipedia.org/wiki/Shared_nothing_architecture
Убрать разделяемое состояние
Но что делать, если потоку X потребовалась какая-то информация, которая
есть у потока Y?
Что делать, если поток Y хочет, чтобы поток Z обновил какие-то данные у
себя?
9
Потокам нужно общаться, но как?
Кажется, что есть два способа:
1. Синхронно.
2. Асинхронно.
Но это только кажется...
10
На самом-то деле...
...никакой синхронности, только хардкор асинхронное взаимодействие.
Например, на основе отсылки и приема сообщений:
● поток X отсылает сообщение-запрос потоку Y;
● поток Y когда-то получит запрос потока X, обработает запрос и отошлет
потоку X ответ;
● поток Y отсылает сообщение-обновление потоку Z;
● поток Z когда-то получит сообщение-обновление от потока Y и обновит
те данные, которые принадлежат потоку Z.
11
Просто же!
Есть потоки. У каждого есть очередь входящих сообщений.
Поток спит, если очередь входящих сообщений пуста.
Поток просыпается, когда для него появляются входящие сообщения.
Если потоку X нужно что-то от потока Y, то X отсылает сообщение в очередь
входящих сообщений потока Y.
Если поток Y хочет ответить потоку X, то Y отсылает сообщение в очередь
входящих сообщений потока X.
12
А если сообщения несут копию данных...
...то мы получаем очень приятный бонус: прозрачный переход к
распределенности.
Если поток Y передал в сообщении Msg копию данных, а не ссылку на них, то
уже не суть важно, пойдет ли сообщение Msg в локальную очередь
входящих сообщений потока Z. Или же в очередь исходящих данных для
передачи на другой хост.
Сообщение самодостаточно. Поэтому может быть сериализовано, передано
по сети, десериализовано и обработано.
13
Вот и весь фокус :)
Модель акторов именно про это.
Про изолированные потоки управления.
И про их взаимодействие на основе обмена сообщениями.
14
Модель Акторов
Появилась в 1973-ем году благодаря работам Карла Хьюитта (Carl Hewitt).
Была затем развита в 1981-ом Уильямом Клингером (William Clinger).
И в 1985-ом Гулом Агха (Gul Agha).
Это если говорить про формализацию Модели Акторов.
Неформально она открывалась и переоткрывалась множество раз.
15
Модель Акторов
Отправные точки для желающих погрузиться в формальную теорию Модели
Акторов:
https://en.wikipedia.org/wiki/History_of_the_Actor_model
https://en.wikipedia.org/wiki/Actor_model
https://en.wikipedia.org/wiki/Actor_model_theory
16
Модель Акторов. Основные принципы
● актор – это некая сущность, обладающая поведением;
● акторы реагируют на входящие сообщения;
● получив сообщение актор может:
○ отослать некоторое (конечное) количество сообщений другим
акторам;
○ создать некоторое (конечное) количество новых акторов;
○ определить для себя новое поведение для обработки последующих
сообщений.
17
Актор – это некоторая сущность
Не более того.
Актором может быть отдельный процесс. Например, Erlang.
Актором может быть отдельный поток (OS thread, "green" thread, fiber, ...).
Например, goroutine в Go может рассматриваться как актор.
Актором может быть объект, которому кто-то выделяет рабочий контекст.
Например, Akka.
18
Еще раз: актор – это некоторая сущность
Модель Акторов не требует, чтобы актор был процессом или потоком, или
конечным автоматом, или чем-то еще.
Поэтому существующие и востребованные на практике реализации Модели
Акторов очень сильно отличаются друг от друга.
19
Модели Акторов уже более 40 лет
За это время Модель Акторов пережила несколько волн популярности и
забвения*
Сейчас очередная волна популярности. Она началась где-то около 10-12 лет
назад. Основным двигателем интереса стали Erlang, а затем Akka.
20* Why has the actor model not succeeded?
Современные иконы: Erlang
Пожалуй, самая известная реализация – язык Erlang*
http://www.erlang.org/
Не только сам язык, но и Erlang VM, и OTP, и вообще все, что понастроили
вокруг.
21* Я не встречал, чтобы Джо Армстронг говорил, что на Erlang повлияла Модель Акторов
Современные иконы: Erlang
Зародился в одной из исследовательских лабораторий Ericsson-а в 1986-ом
году благодаря Джо Армстронгу (Joe Armstrong).
В 1995-ом году после закрытия неудачного проекта AXE-N (на C++, кстати)
был выбран в качестве основного языка для проекта AXD.
Результатом стал успешный программно-аппаратный продукт AXD301 в
котором было более миллиона строк на Erlang.
22
Современные иконы: Erlang
В конце 1990-х использование Erlang-а для новых проектов в Ericsson Radio
AB было запрещено.
Джо Армстронг покинул Ericsson.
Erlang ушел в OpenSource.
Erlang доказал свою состоятельность вне Ericsson-а. Ericsson одумался.
В 2004-ом году Джо Армстронг возвратился в Ericsson.
23
Современные иконы: Erlang
За последние годы Erlang многократно показывал себя с лучшей стороны в
очень серьезных проектах (например, WhatsApp использует Erlang).
Многие компании убедившись в достоинствах Erlang-а задействуют Erlang в
своих разработках.
Из близких нам примеров: Wargaming.
24
Современные иконы: Erlang
-module(tut15).
-export([start/0, ping/2, pong/0]).
ping(0, Pong_PID) ->
Pong_PID ! finished,
io:format("ping finished~n", []);
ping(N, Pong_PID) ->
Pong_PID ! {ping, self()},
receive
pong ->
io:format("Ping received pong~n", [])
end,
ping(N - 1, Pong_PID).
25
pong() ->
receive
finished ->
io:format("Pong finished~n", []);
{ping, Ping_PID} ->
io:format("Pong received ping~n", []),
Ping_PID ! pong,
pong()
end.
start() ->
Pong_PID = spawn(tut15, pong, []),
spawn(tut15, ping, [3, Pong_PID]).
Современные иконы: Akka
Фреймворк для Java и Scala.
http://akka.io/
История началась в 2006: Филипп Холлер (Philipp Haller) разработал
реализацию Модели Акторов для стандартной библиотеки языка Scala.
В 2008-ом Джонас Бонер (Jonas Bonér) начал делать Erlang-овский OTP для
Scala на базе акторов из Scala-stdlib*. Первая публичная версия Akka вышла
в 2010-ом.
26* http://www.lightbend.com/akka-five-year-anniversary
Современные иконы: Akka
Очень популярна в JVM-мире.
Соответственно, находит широкое применение там, где позиции JVM
традиционно сильны: Web, онлайн-сервисы и суровый энтерпрайз...
Яркие примеры: LinkedIn и Twitter.
Стоящие за Akka люди так же причастны к таким современным buzz-word-ам,
как Reactive Manifesto* и Microservices** :)
27
* http://www.reactivemanifesto.org/
** https://en.wikipedia.org/wiki/Microservices
Современные иконы: Akka
import akka.actor._
case object PingMessage
case object PongMessage
case object StartMessage
case object StopMessage
class Ping(pong: ActorRef) extends Actor {
var count = 0
def incrementAndPrint { count += 1; println("ping") }
def receive = {
case StartMessage =>
incrementAndPrint
pong ! PingMessage
case PongMessage =>
incrementAndPrint
if (count > 99) {
sender ! StopMessage
println("ping stopped")
context.stop(self)
} else {
sender ! PingMessage
}
28
}
}
class Pong extends Actor {
def receive = {
case PingMessage =>
println(" pong")
sender ! PongMessage
case StopMessage =>
println("pong stopped")
context.stop(self)
}
}
object PingPongTest extends App {
val system = ActorSystem("PingPongSystem")
val pong = system.actorOf(Props[Pong], name = "pong")
val ping = system.actorOf(Props(new Ping(pong)), name = "ping")
// start them going
ping ! StartMessage
}
http://alvinalexander.com/scala/scala-akka-actors-ping-pong-simple-example
В чем сила, брат?
Что же такое предлагают своим пользователям Erlang и Akka?
Почему они востребованы и используются в очень серьезных проектах?
29
Вот в чем:
1. Простота. Отсутствие разделяемых данных и взаимодействие
посредством асинхронных сообщений спасают от ужасов
программирования на мьютексах.
2. Масштабирование. Акторов может быть хоть миллион. Даже самую
мелкую задачку можно поручить отдельному актору. Акторов можно
распределять по нескольким процессам и нескольким нодам, при
асинхронном обмене сообщениями это не суть важно.
3. Отказоустойчивость. Какие-то акторы могут "падать", другие акторы
это обнаружат и исправят (см. систему супервизоров Erlang-а*). Shared
nothing + message-passing сильно помогают и тут.
30* http://erlang.org/doc/man/supervisor.html
Так говорил Джо Армстронг
I also suspect that the advent of true parallel CPU cores will make
programming parallel systems using conventional mutexes and
shared data structures almost impossibly difficult, and that the pure
message-passing systems will become the dominant way to program
parallel systems.
Так же я подозреваю, что пришествие настоящих многоядерных CPU сделает
программирование параллельных систем с использованием традиционных мьютексов и
разделяемых структур данных сложным до невозможности, и что именно обмен
сообщениями станет доминирующим способом разработки параллельных систем.
Disclaimer: перевод приблизительный, но основной смысл передан верно.
31A History of Erlang, Joe Armstrong, 2007.
Кстати об отказоустойчивости
Erlang и Java/Scala (речь об Akka) – это безопасные языки, работающие в
управляемых средах (Erlang VM и JVM).
На отказоустойчивость это влияет самым непосредственным образом.
Деление на ноль в одном из процессов внутри Erlang VM и деление на ноль в
одном из потоков большого приложения на C++ – это две большие разницы.
32
А что с C++?
Есть ли смысл в использовании Модели Акторов в C++?
33
Неверный вопрос!
Начинать нужно с более важного вопроса:
А нужен ли вообще C++?
34
Серьезно? И это на CoreHard C++?
Таки да :(
35
Так нужен ли вообще C++?
С++ старый язык (более 30 лет с публичного релиза).
За это время стал настоящим монстром, стандарт которого насчитывает
~1500 страниц. И это еще C++17 не приняли...
Вобрал в себя множество нового (в переводе на русский: стал еще сложнее).
Сохранил при этом совместимость с еще более древним языком С. Так что с
отстрелом конечностей все в порядке.
Каждый большой проект использует собственное подмножество C++.
Огромное количество копролитов мамонта легаси кода.
36
Тем не менее...
...какой еще мейнстримовый нативный язык без GC:
● настолько же быстр и эффективен?
● позволяет работать на самом низком уровне?
● позволяет подниматься на высокие уровни абстракции (ООП,
обобщенное программирование, метапрограммирование)?
● снабжен таким же количеством разнообразного инструментария?
● так же хорошо и досконально описан в огромном количестве книг,
статей, руководств, рекомендаций и пр.?
● обладает таким же большим коммьюнити?
Если объективно посмотреть по сторонам, то альтернатив не так уж и много.
37
Вывод прост: нужен, однозначно!
А раз нужен, то нужны и инструменты, облегчающие жизнь C++
разработчикам.
В том числе и реализации Модели Акторов для C++.
38
Больше фреймворков, хороших и разных!
Более-менее актуальный список инструментов для C++ можно найти здесь:
https://en.wikipedia.org/wiki/Actor_model#Actor_libraries_and_frameworks
Там не все. А часть того, что есть, уже умерло. Но все-таки.
39
Четверо смелых для беглого знакомства
Далее быстрый забег "по верхам" для знакомства с четырьмя C++
фреймворками, которые:
● на C++;
● подают признаки жизни (что уже не мало, на самом-то деле);
● кросс-платформенны;
● интересны с той или иной стороны.
Есть еще, например, OOSMOS* и Asyncronous Agents Library** от MS, но они
не вошли в обзор из-за нарушения каких-то из перечисленных выше пунктов.
40
* http://www.oosmos.com/
** https://msdn.microsoft.com/en-us/library/dd492627.aspx
QP/C++
http://www.state-machine.com/qpcpp/
C++98/03. Предназначен для разработки встраиваемого ПО. В том числе и
для работы на голом железе.
Двойная лицензия.
Более 15 лет развития и эксплуатации.
Декларируется приличный уровень соответствия MISRA C++2008.
41
QP/C++
Акторы в QP/C++ – это иерархические конечные автоматы. Называются
активными объектами.
Код активных объектов можно писать обычным образом. Т.е. вручную
набирать код C++ классов, методов и вот это вот все.
А можно "нарисовать" активный объект в специальном визуальном
инструменте для проектирования и C++ код будет сгенерирован.
Контекст для работы активных объектов предоставляет QP. В зависимости
от окружения активные объекты могут работать на отдельных нитях. А могут
и сообща на одной-единственной.
42
QP/C++ (пример кода: blinky.h)
#ifndef blinky_h
#define blinky_h
using namespace QP;
enum BlinkySignals {
DUMMY_SIG = Q_USER_SIG,
MAX_PUB_SIG, // the last published signal
TIMEOUT_SIG,
MAX_SIG // the last signal
};
extern QMActive * const AO_Blinky; // opaque pointer
#endif // blinky_h
43
QP/C++ (пример кода: main.cpp)
#include "qpcpp.h"
#include "bsp.h"
#include "blinky.h"
int main() {
static QEvt const *blinkyQSto[10]; // Event queue storage for Blinky
BSP_init(); // initialize the Board Support Package
QF::init(); // initialize the framework and the underlying RT kernel
// instantiate and start the active objects...
AO_Blinky->start(1U, // priority
blinkyQSto, Q_DIM(blinkyQSto), // event queue
(void *)0, 0U); // stack (unused)
return QF::run(); // run the QF application
}
44
QP/C++ (пример кода: blinky.cpp, 1)
#include "qpcpp.h"
#include "bsp.h"
#include "blinky.h"
class Blinky : public QActive {
private:
QTimeEvt m_timeEvt;
public:
Blinky();
protected:
static QState initial(Blinky * const me, QEvt const * const e);
static QState off(Blinky * const me, QEvt const * const e);
static QState on(Blinky * const me, QEvt const * const e);
};
Blinky l_blinky;
QMActive * const AO_Blinky = &l_blinky; // opaque pointer
45
QP/C++ (пример кода: blinky.cpp, 2)
Blinky::Blinky()
: QActive(Q_STATE_CAST(&Blinky::initial)),
m_timeEvt(this, TIMEOUT_SIG, 0U)
{}
QState Blinky::initial(Blinky * const me, QEvt const * const e) {
(void)e; // unused parameter
// arm the time event to expire in half a second and every half second
me->m_timeEvt.armX(BSP_TICKS_PER_SEC/2U, BSP_TICKS_PER_SEC/2U);
return Q_TRAN(&Blinky::off);
}
46
QP/C++ (пример кода: blinky.cpp, 3)
QState Blinky::off(Blinky * const me, QEvt const * const e)
{
QState status;
switch (e->sig) {
case Q_ENTRY_SIG: {
BSP_ledOff();
status = Q_HANDLED();
break;
}
case TIMEOUT_SIG: {
status = Q_TRAN(&Blinky::on);
break;
}
default: {
status = Q_SUPER(&QHsm::top);
break;
}
}
return status;
}
47
QState Blinky::on(Blinky * const me, QEvt const * const e)
{
QState status;
switch (e->sig) {
case Q_ENTRY_SIG: {
BSP_ledOn();
status = Q_HANDLED();
break;
}
case TIMEOUT_SIG: {
status = Q_TRAN(&Blinky::off);
break;
}
default: {
status = Q_SUPER(&QHsm::top);
break;
}
}
return status;
}
Just::Thread Pro: Actors Edition
http://www.stdthread.co.uk/pro/
C++11.
Платная библиотека.
Автор – Энтони Уильямс (Anthony Williams). Он же написал книгу "C++
Concurrency in Action".
На этом, пожалуй, достоинства заканчиваются :)
Под каждого актора выделяется отдельный поток ОС.
48
Just::Thread Pro: Actors Edition (ping-pong)
#include <jss/actor.hpp>
#include <iostream>
#include <thread>
int main()
{
struct pingpong {
jss::actor_ref sender;
pingpong(jss::actor_ref sender_): sender(sender_) {}
};
jss::actor pp1(
[]{
for(;;)
{
jss::actor::receive().match<pingpong>(
[](pingpong p){
std::cout<<"pingn";
p.sender.send(pingpong(jss::actor::self()));
});
}
});
49
jss::actor pp2(
[]{
for(;;)
{
jss::actor::receive().match<pingpong>(
[](pingpong p){
std::cout<<"pongn";
p.sender.send(pingpong(jss::actor::self()));
});
}
});
pp1.send(pingpong(pp2));
std::this_thread::sleep_for(std::chrono::seconds(2));
pp1.stop();
pp2.stop();
}
C++ Actor Framework (он же CAF)
http://www.actor-framework.org/
C++11 и выше (чем выше, тем лучше).
OpenSource под BSD-3-CLAUSE лицензией.
Самая распиаренная реализация Модели Акторов для C++.
Позиционирует себя как очень быстрый фреймворк. Не то, чтобы так уж
заслуженно* ;)
Пока еще не стабилизировался.
50* Performance Comparison SO-5.5.15.2 vs CAF-0.14.4
C++ Actor Framework (он же CAF)
Изначально копировал Erlang в C++ настолько близко, насколько это
возможно. Постепенно видоизменяется и приобретает свои уникальные
черты.
Ценой за мимикрию под Erlang являются высокие требования CAF-а к
уровню поддержки стандартов в C++ в компиляторе.
Официальная поддержка Windows/VC++ появилась только после выхода
Visual Studio 2015 update 3.
Есть поддержка распределенности. Собственный протокол с реализацией на
базе Boost::Asio.
51
C++ Actor Framework (fixed_stack, 1)
#include <cassert>
#include <cstdint>
#include <iostream>
#include "caf/all.hpp"
using std::endl;
using namespace caf;
namespace {
using pop_atom = atom_constant<atom("pop")>;
using push_atom = atom_constant<atom("push")>;
enum class fixed_stack_errc : uint8_t { push_to_full = 1, pop_from_empty };
error make_error(fixed_stack_errc x) {
return error{static_cast<uint8_t>(x), atom("FixedStack")};
}
52
C++ Actor Framework (fixed_stack, 2)
class fixed_stack : public event_based_actor {
public:
fixed_stack(actor_config& cfg, size_t stack_size)
: event_based_actor(cfg),
size_(stack_size) {
full_.assign(
[=](push_atom, int) -> error {
return fixed_stack_errc::push_to_full;
},
[=](pop_atom) -> int {
auto result = data_.back();
data_.pop_back();
become(filled_);
return result;
}
);
53
C++ Actor Framework (fixed_stack, 3)
filled_.assign(
[=](push_atom, int what) {
data_.push_back(what);
if (data_.size() == size_)
become(full_);
},
[=](pop_atom) -> int {
auto result = data_.back();
data_.pop_back();
if (data_.empty())
become(empty_);
return result;
}
);
54
C++ Actor Framework (fixed_stack, 4)
empty_.assign(
[=](push_atom, int what) {
data_.push_back(what);
become(filled_);
},
[=](pop_atom) -> error {
return fixed_stack_errc::pop_from_empty;
}
);
}
55
C++ Actor Framework (fixed_stack, 5)
behavior make_behavior() override {
assert(size_ < 2);
return empty_;
}
private:
size_t size_;
std::vector<int> data_;
behavior full_;
behavior filled_;
behavior empty_;
};
56
C++ Actor Framework (fixed_stack, 6)
void caf_main(actor_system& system) {
scoped_actor self{system};
auto st = self->spawn<fixed_stack>(5u);
// fill stack
for (int i = 0; i < 10; ++i) self->send(st, push_atom::value, i);
// drain stack
aout(self) << "stack: { ";
bool stack_empty = false;
while (!stack_empty) {
self->request(st, std::chrono::seconds(10), pop_atom::value).receive(
[&](int x) {
aout(self) << x << " ";
},
[&](const error&) {
stack_empty = true;
}
);
}
aout(self) << "}" << endl;
self->send_exit(st, exit_reason::user_shutdown);
}
} // namespace <anonymous>
CAF_MAIN()
57
SObjectizer-5
https://sourceforge.net/projects/sobjectizer/ или https://github.com/eao197/so-5-5
C++11 (минимальные требования к компилятору: GCC 4.8, MSVC++12.0).
OpenSource под BSD-3-CLAUSE лицензией.
С очень долгой историей:
1995-2000: Гомель, КБ Системного Программирования, проект SCADA Objectizer;
2002-...: Гомель-Москва, Интервэйл, проект SObjectizer-4;
2010-...: Гомель-Москва, Интервэйл, The SObjectizer Team, проект SObjectizer-5.
58
SObjectizer-5
SO-4 в продакшене c 2002-го года. И до сих пор работает.
SO-5 в продакшене с 2011-го года.
Обратная совместимость – must have.
Без фанатизма, но позволить себе вносить ломающие совместимость
изменения в каждый релиз мы не можем. От слова совсем.
Версия SO-5.5.0 вышла в октябре 2014-го. С тех пор в ветке 5.5.* нет ломающих
изменений. Последняя стабильная версия 5.5.18 – сентябрь 2016.
59
SObjectizer-5
Акторы в SO-5 называются агентами. Так сложилось.
Агенты в SO-5 – это иерархические конечные автоматы (вложенные
состояния, обработчики входа-выхода, история, временные лимиты).
Рабочий контекст агентам предоставляют диспетчеры.
Разработчику "из коробки" доступно восемь типов готовых диспетчеров.
Распределенность в SO-5 не поддерживается. Был опыт в SO-4. Поэтому в
SO-5 решили обходиться готовыми сторонними инструментами по задачу
(MQTT, AMQP, HTTP и т.д.).
60
SObjectizer-5
Главное отличие от прочих фреймворков: SO-5 – это симбиоз Модели
Акторов, модели Publish/Subscribe. С элементами CSP*
Сообщения отсылаются не агенту, а в message box (mbox). За mbox-ом
может быть один агент, может быть множество агентов. Или ни одного.
Mbox является аналогом Topic-а из Pub/Sub. Отсылка сообщения – аналогом
Publish-а из Pub/Sub. И, как и в Pub/Sub, агент должен подписаться на
сообщение, чтобы получить его.
61* https://en.wikipedia.org/wiki/Communicating_sequential_processes
SObjectizer-5 (blinking_led, 1)
#include <iostream>
#include <so_5/all.hpp>
class blinking_led final : public so_5::agent_t
{
state_t off{ this }, blinking{ this },
blink_on{ initial_substate_of{ blinking } },
blink_off{ substate_of{ blinking } };
public :
struct turn_on_off : public so_5::signal_t {};
62
SObjectizer-5 (blinking_led, 2)
blinking_led( context_t ctx ) : so_5::agent_t{ ctx }
{
this >>= off;
off.just_switch_to< turn_on_off >( blinking );
blinking.just_switch_to< turn_on_off >( off );
blink_on
.on_enter( []{ std::cout << "ON" << std::endl; } )
.on_exit( []{ std::cout << "off" << std::endl; } )
.time_limit( std::chrono::milliseconds{1250}, blink_off );
blink_off
.time_limit( std::chrono::milliseconds{750}, blink_on );
}
};
63
SObjectizer-5 (blinking_led, 3)
int main() {
so_5::launch( []( so_5::environment_t & env ) {
so_5::mbox_t m;
env.introduce_coop( [&]( so_5::coop_t & coop ) {
auto led = coop.make_agent< blinking_led >();
m = led->so_direct_mbox();
} );
auto pause = []( unsigned int v ) { std::this_thread::sleep_for( std::chrono::seconds{v} ); };
so_5::send< blinking_led::turn_on_off >( m );
pause( 10 );
so_5::send< blinking_led::turn_on_off >( m );
pause( 5 );
so_5::send< blinking_led::turn_on_off >( m );
pause( 5 );
env.stop();
} );
}
64
Заключение 1/3
Модель Акторов – это очень удобный инструмент в случаях, где
использование этой модели уместно1
.
Это уже неоднократно доказывалось успешным применением таких
инструментов, как Erlang и Akka в самых разнообразных проектах.
Да и вообще за асинхронным обменом сообщений между независимыми
сущностями будущее. Прислушайтесь к Джо Армстронгу, он плохого не
посоветует ;)
1)
Не верьте рекламе: уместно не везде.
65
Заключение 2/3
Наш опыт показывает, что при наличии подходящих инструментов Модель
Акторов имеет смысл применять и в C++.
При этом для C++ подходящие готовые инструменты уже есть.
На разный вкус и цвет.
И размер кошелька, конечно же.
В коммерческом проекте за QP/C++ и за Just::Thread Pro придется заплатить.
За SObjectizer и CAF – нет. По крайней мере сразу не придется.
66
Заключение 3/3
Вот чего делать не стоит, так это браться за написание собственного
акторного фреймворка.
Неблагодарное это дело. Проверено. На людях.
Лучше все-таки взять что-то готовое. Hint: купляйце беларускае.
И пусть кто-нибудь другой весело бегает по граблям многопоточности :)
67
Спасибо за терпение!
Вопросы?
68
Bonus track (SO-5's fixed_stack, 1)
#include <iostream>
#include <so_5/all.hpp>
class fixed_stack final : public so_5::agent_t
{
state_t st_empty{ this },
st_filled{ this },
st_full{ this };
const size_t m_max_size;
std::vector< int > m_stack;
public :
class empty_stack final : public std::logic_error
{
public :
using std::logic_error::logic_error;
};
struct push { int m_val; };
struct pop : public so_5::signal_t {};
69* https://bitbucket.org/sobjectizerteam/fixed_stack_example
Bonus track (SO-5's fixed_stack, 2)
fixed_stack( context_t ctx, size_t max_size )
: so_5::agent_t( ctx )
, m_max_size( max_size )
{
this >>= st_empty;
so_subscribe_self()
.in( st_empty )
.in( st_filled )
.event( &fixed_stack::on_push );
so_subscribe_self()
.in( st_filled )
.in( st_full )
.event( &fixed_stack::on_pop_when_not_empty );
so_subscribe_self()
.in( st_empty )
.event( &fixed_stack::on_pop_when_empty );
}
70
Bonus track (SO-5's fixed_stack, 3)
private :
void on_push( const push & w )
{
m_stack.push_back( w.m_val );
this >>= ( m_stack.size() == m_max_size ? st_full : st_filled );
}
int on_pop_when_not_empty( mhood_t< pop > )
{
auto r = m_stack.back();
m_stack.pop_back();
this >>= ( m_stack.empty() ? st_empty : st_filled );
return r;
}
int on_pop_when_empty( mhood_t< pop > )
{
throw empty_stack( "empty_stack" );
}
};
71
Bonus track (SO-5's fixed_stack, 4)
int main() {
try {
so_5::launch( []( so_5::environment_t & env ) {
so_5::mbox_t stack;
env.introduce_coop( [&stack]( so_5::coop_t & coop ) {
stack = coop.make_agent< fixed_stack >( 5u )->so_direct_mbox();
} );
for( int i = 0; i < 10; ++i ) so_5::send< fixed_stack::push >( stack, i );
std::cout << "stack { ";
try {
for(;;)
std::cout << so_5::request_value< int, fixed_stack::pop >( stack, std::chrono::seconds(10) ) << " ";
}
catch( const fixed_stack::empty_stack & ) {}
std::cout << "}" << std::endl;
env.stop();
} );
return 0;
}
catch( const std::exception & x ) {
std::cerr << "Oops! " << x.what() << std::endl;
}
return 2;
}
72
Документация по SObjectizer: https://sourceforge.net/p/sobjectizer/wiki/Home/
Серия статей о SObjectizer на русском:
SObjectizer: что это, для чего это и почему это выглядит именно так? От простого к сложному:
Часть I, Часть II, Часть III. Акторы в виде конечных автоматов – это плохо или хорошо?
Проблема перегрузки агентов и средства борьбы с ней. Нежная дружба агентов и
исключений.
Серия презентаций о SObjectizer на английском "Dive into SObjectizer-5.5":
Intro, Agent's States, More About Coops, Exceptions, Timers, Synchonous Interaction, Message
Limits, Dispatchers, Message Chains.
Блог автора доклада: eao197.blogspot.com
О SObjectizer в блоге: eao197.blogspot.com/search/label/SObjectizer
Почта автора доклада: eao197 на gmail тчк com
73

More Related Content

What's hot

Scala: что, как и зачем?
Scala: что, как и зачем?Scala: что, как и зачем?
Scala: что, как и зачем?
Roman Timushev
 
Лекция 8: Многопоточное программирование: Intel Threading Building Blocks
Лекция 8: Многопоточное программирование: Intel Threading Building BlocksЛекция 8: Многопоточное программирование: Intel Threading Building Blocks
Лекция 8: Многопоточное программирование: Intel Threading Building Blocks
Mikhail Kurnosov
 
Глава 3: примитивные типы и операции с ними в Java
Глава 3: примитивные типы и операции с ними в JavaГлава 3: примитивные типы и операции с ними в Java
Глава 3: примитивные типы и операции с ними в Java
metaform
 
Deep Dive C# by Sergey Teplyakov
Deep Dive  C# by Sergey TeplyakovDeep Dive  C# by Sergey Teplyakov
Deep Dive C# by Sergey Teplyakov
Alex Tumanoff
 
Базовые операторы Java
Базовые операторы JavaБазовые операторы Java
Базовые операторы Java
metaform
 

What's hot (20)

Алексей Куканов — Параллелизм в C++: управляйте приложением, а не потоками!
Алексей Куканов — Параллелизм в C++: управляйте приложением, а не потоками!Алексей Куканов — Параллелизм в C++: управляйте приложением, а не потоками!
Алексей Куканов — Параллелизм в C++: управляйте приложением, а не потоками!
 
Scala: что, как и зачем?
Scala: что, как и зачем?Scala: что, как и зачем?
Scala: что, как и зачем?
 
Scala для всех (РИФ 2015)
Scala для всех (РИФ 2015)Scala для всех (РИФ 2015)
Scala для всех (РИФ 2015)
 
Лекция 8: Многопоточное программирование: Intel Threading Building Blocks
Лекция 8: Многопоточное программирование: Intel Threading Building BlocksЛекция 8: Многопоточное программирование: Intel Threading Building Blocks
Лекция 8: Многопоточное программирование: Intel Threading Building Blocks
 
C++ Базовый. Занятие 02.
C++ Базовый. Занятие 02.C++ Базовый. Занятие 02.
C++ Базовый. Занятие 02.
 
Ввведение в java
Ввведение в javaВвведение в java
Ввведение в java
 
Александр Фокин, Рефлексия в C++
Александр Фокин, Рефлексия в C++Александр Фокин, Рефлексия в C++
Александр Фокин, Рефлексия в C++
 
Дизайн больших приложений в ФП
Дизайн больших приложений в ФПДизайн больших приложений в ФП
Дизайн больших приложений в ФП
 
Java. Cистемы счислния, битовые операции
Java. Cистемы счислния, битовые операцииJava. Cистемы счислния, битовые операции
Java. Cистемы счислния, битовые операции
 
Java. Строки. Класс String.
Java. Строки. Класс String.Java. Строки. Класс String.
Java. Строки. Класс String.
 
Глава 3: примитивные типы и операции с ними в Java
Глава 3: примитивные типы и операции с ними в JavaГлава 3: примитивные типы и операции с ними в Java
Глава 3: примитивные типы и операции с ними в Java
 
Для чего мы делали свой акторный фреймворк и что из этого вышло?
Для чего мы делали свой акторный фреймворк и что из этого вышло?Для чего мы делали свой акторный фреймворк и что из этого вышло?
Для чего мы делали свой акторный фреймворк и что из этого вышло?
 
Discovering Lambdas (Speech)
Discovering Lambdas (Speech)Discovering Lambdas (Speech)
Discovering Lambdas (Speech)
 
Back to the future: Функциональное программирование вчера и сегодня
Back to the future: Функциональное программирование вчера и сегодняBack to the future: Функциональное программирование вчера и сегодня
Back to the future: Функциональное программирование вчера и сегодня
 
Никита Глушков, К вопросу о реализации кроссплатформенных фреймворков
Никита Глушков, К вопросу о реализации кроссплатформенных фреймворковНикита Глушков, К вопросу о реализации кроссплатформенных фреймворков
Никита Глушков, К вопросу о реализации кроссплатформенных фреймворков
 
C++ Базовый. Занятие 04.
C++ Базовый. Занятие 04.C++ Базовый. Занятие 04.
C++ Базовый. Занятие 04.
 
Deep Dive C# by Sergey Teplyakov
Deep Dive  C# by Sergey TeplyakovDeep Dive  C# by Sergey Teplyakov
Deep Dive C# by Sergey Teplyakov
 
Базовые операторы Java
Базовые операторы JavaБазовые операторы Java
Базовые операторы Java
 
Борис Сазонов, RAII потоки и CancellationToken в C++
Борис Сазонов, RAII потоки и CancellationToken в C++Борис Сазонов, RAII потоки и CancellationToken в C++
Борис Сазонов, RAII потоки и CancellationToken в C++
 
Лекция 8. Intel Threading Building Blocks
Лекция 8. Intel Threading Building BlocksЛекция 8. Intel Threading Building Blocks
Лекция 8. Intel Threading Building Blocks
 

Viewers also liked

Viewers also liked (12)

C++ game development with oxygine
C++ game development with oxygineC++ game development with oxygine
C++ game development with oxygine
 
Actor Model and C++: what, why and how?
Actor Model and C++: what, why and how?Actor Model and C++: what, why and how?
Actor Model and C++: what, why and how?
 
Unit tests final
Unit tests finalUnit tests final
Unit tests final
 
шишки, набитые за 15 лет использования акторов в c++ v.001.3
шишки, набитые за 15 лет использования акторов в c++ v.001.3шишки, набитые за 15 лет использования акторов в c++ v.001.3
шишки, набитые за 15 лет использования акторов в c++ v.001.3
 
Mixing d ps building architecture on the cross cutting example
Mixing d ps building architecture on the cross cutting exampleMixing d ps building architecture on the cross cutting example
Mixing d ps building architecture on the cross cutting example
 
Современный статический анализ кода: что умеет он, чего не умели линтеры
Современный статический анализ кода: что умеет он, чего не умели линтерыСовременный статический анализ кода: что умеет он, чего не умели линтеры
Современный статический анализ кода: что умеет он, чего не умели линтеры
 
Диаграммы состояний и c++
Диаграммы состояний и c++Диаграммы состояний и c++
Диаграммы состояний и c++
 
C++ references
C++ referencesC++ references
C++ references
 
Повседневный С++: алгоритмы и итераторы
Повседневный С++: алгоритмы и итераторы Повседневный С++: алгоритмы и итераторы
Повседневный С++: алгоритмы и итераторы
 
Reactive Stream Processing in Industrial IoT using DDS and Rx
Reactive Stream Processing in Industrial IoT using DDS and RxReactive Stream Processing in Industrial IoT using DDS and Rx
Reactive Stream Processing in Industrial IoT using DDS and Rx
 
C++ Generators and Property-based Testing
C++ Generators and Property-based TestingC++ Generators and Property-based Testing
C++ Generators and Property-based Testing
 
строим Microkernel architecture на базе паттерна pipes and filters
строим Microkernel architecture на базе паттерна pipes and filtersстроим Microkernel architecture на базе паттерна pipes and filters
строим Microkernel architecture на базе паттерна pipes and filters
 

Similar to модель акторов и C++ что, зачем и как ?

лекция1
лекция1лекция1
лекция1
shagore
 
Акторы в C++: взгляд старого практикующего актородела (St. Petersburg C++ Use...
Акторы в C++: взгляд старого практикующего актородела (St. Petersburg C++ Use...Акторы в C++: взгляд старого практикующего актородела (St. Petersburg C++ Use...
Акторы в C++: взгляд старого практикующего актородела (St. Petersburg C++ Use...
Yauheni Akhotnikau
 
noBackend, или Как выжить в эпоху толстеющих клиентов / Самохвалов Николай
noBackend, или Как выжить в эпоху толстеющих клиентов / Самохвалов НиколайnoBackend, или Как выжить в эпоху толстеющих клиентов / Самохвалов Николай
noBackend, или Как выжить в эпоху толстеющих клиентов / Самохвалов Николай
Ontico
 
Tech Talks @NSU: Как приручить дракона: введение в LLVM
Tech Talks @NSU: Как приручить дракона: введение в LLVMTech Talks @NSU: Как приручить дракона: введение в LLVM
Tech Talks @NSU: Как приручить дракона: введение в LLVM
Tech Talks @NSU
 
Android: Как написать приложение, которое не тормозит
Android: Как  написать приложение, которое не тормозитAndroid: Как  написать приложение, которое не тормозит
Android: Как написать приложение, которое не тормозит
Elena Kotina
 
Многопоточное Программирование - Теория и Практика
Многопоточное Программирование - Теория и ПрактикаМногопоточное Программирование - Теория и Практика
Многопоточное Программирование - Теория и Практика
Roman Elizarov
 

Similar to модель акторов и C++ что, зачем и как ? (20)

Руслан Гроховецкий "Как Python стал делать погоду в Яндексе"
Руслан Гроховецкий "Как Python стал делать погоду в Яндексе"Руслан Гроховецкий "Как Python стал делать погоду в Яндексе"
Руслан Гроховецкий "Как Python стал делать погоду в Яндексе"
 
Как жить в согласии с SOLID?
Как жить в согласии с SOLID?Как жить в согласии с SOLID?
Как жить в согласии с SOLID?
 
лекция1
лекция1лекция1
лекция1
 
Акторы в C++: взгляд старого практикующего актородела (St. Petersburg C++ Use...
Акторы в C++: взгляд старого практикующего актородела (St. Petersburg C++ Use...Акторы в C++: взгляд старого практикующего актородела (St. Petersburg C++ Use...
Акторы в C++: взгляд старого практикующего актородела (St. Petersburg C++ Use...
 
Уроки Scratch
Уроки Scratch Уроки Scratch
Уроки Scratch
 
#noBackend, или Как выжить в эпоху толстеющих клиентов
#noBackend, или Как выжить в эпоху толстеющих клиентов#noBackend, или Как выжить в эпоху толстеющих клиентов
#noBackend, или Как выжить в эпоху толстеющих клиентов
 
noBackend, или Как выжить в эпоху толстеющих клиентов / Самохвалов Николай
noBackend, или Как выжить в эпоху толстеющих клиентов / Самохвалов НиколайnoBackend, или Как выжить в эпоху толстеющих клиентов / Самохвалов Николай
noBackend, или Как выжить в эпоху толстеющих клиентов / Самохвалов Николай
 
Discovering Lambdas in Java 8
Discovering Lambdas in Java 8Discovering Lambdas in Java 8
Discovering Lambdas in Java 8
 
Tech Talks @NSU: Как приручить дракона: введение в LLVM
Tech Talks @NSU: Как приручить дракона: введение в LLVMTech Talks @NSU: Как приручить дракона: введение в LLVM
Tech Talks @NSU: Как приручить дракона: введение в LLVM
 
Как приручить дракона: введение в LLVM
Как приручить дракона: введение в LLVMКак приручить дракона: введение в LLVM
Как приручить дракона: введение в LLVM
 
Denys Samoylenko ''JS learning lifehacks: common programmer's mistake''
Denys Samoylenko ''JS learning lifehacks: common programmer's mistake''Denys Samoylenko ''JS learning lifehacks: common programmer's mistake''
Denys Samoylenko ''JS learning lifehacks: common programmer's mistake''
 
KL10TCH: Paver.js + T.js
KL10TCH: Paver.js + T.jsKL10TCH: Paver.js + T.js
KL10TCH: Paver.js + T.js
 
C++ CoreHard Autumn 2018. Actors vs CSP vs Tasks vs ... - Евгений Охотников
C++ CoreHard Autumn 2018. Actors vs CSP vs Tasks vs ... - Евгений ОхотниковC++ CoreHard Autumn 2018. Actors vs CSP vs Tasks vs ... - Евгений Охотников
C++ CoreHard Autumn 2018. Actors vs CSP vs Tasks vs ... - Евгений Охотников
 
C sharp deep dive
C sharp deep diveC sharp deep dive
C sharp deep dive
 
C# Deep Dive
C# Deep DiveC# Deep Dive
C# Deep Dive
 
Платформа SmartActors
Платформа SmartActorsПлатформа SmartActors
Платформа SmartActors
 
Android: Как написать приложение, которое не тормозит
Android: Как  написать приложение, которое не тормозитAndroid: Как  написать приложение, которое не тормозит
Android: Как написать приложение, которое не тормозит
 
Большой брат помогает тебе
Большой брат помогает тебеБольшой брат помогает тебе
Большой брат помогает тебе
 
СИ++ УМЕР. ДА ЗДРАВСТВУЕТ СИ++
СИ++ УМЕР. ДА ЗДРАВСТВУЕТ СИ++СИ++ УМЕР. ДА ЗДРАВСТВУЕТ СИ++
СИ++ УМЕР. ДА ЗДРАВСТВУЕТ СИ++
 
Многопоточное Программирование - Теория и Практика
Многопоточное Программирование - Теория и ПрактикаМногопоточное Программирование - Теория и Практика
Многопоточное Программирование - Теория и Практика
 

More from corehard_by

C++ CoreHard Autumn 2018. Обработка списков на C++ в функциональном стиле - В...
C++ CoreHard Autumn 2018. Обработка списков на C++ в функциональном стиле - В...C++ CoreHard Autumn 2018. Обработка списков на C++ в функциональном стиле - В...
C++ CoreHard Autumn 2018. Обработка списков на C++ в функциональном стиле - В...
corehard_by
 
C++ CoreHard Autumn 2018. Debug C++ Without Running - Anastasia Kazakova
C++ CoreHard Autumn 2018. Debug C++ Without Running - Anastasia KazakovaC++ CoreHard Autumn 2018. Debug C++ Without Running - Anastasia Kazakova
C++ CoreHard Autumn 2018. Debug C++ Without Running - Anastasia Kazakova
corehard_by
 
C++ CoreHard Autumn 2018. Text Formatting For a Future Range-Based Standard L...
C++ CoreHard Autumn 2018. Text Formatting For a Future Range-Based Standard L...C++ CoreHard Autumn 2018. Text Formatting For a Future Range-Based Standard L...
C++ CoreHard Autumn 2018. Text Formatting For a Future Range-Based Standard L...
corehard_by
 

More from corehard_by (20)

C++ CoreHard Autumn 2018. Создание пакетов для открытых библиотек через conan...
C++ CoreHard Autumn 2018. Создание пакетов для открытых библиотек через conan...C++ CoreHard Autumn 2018. Создание пакетов для открытых библиотек через conan...
C++ CoreHard Autumn 2018. Создание пакетов для открытых библиотек через conan...
 
C++ CoreHard Autumn 2018. Что должен знать каждый C++ программист или Как про...
C++ CoreHard Autumn 2018. Что должен знать каждый C++ программист или Как про...C++ CoreHard Autumn 2018. Что должен знать каждый C++ программист или Как про...
C++ CoreHard Autumn 2018. Что должен знать каждый C++ программист или Как про...
 
C++ CoreHard Autumn 2018. Знай свое "железо": иерархия памяти - Александр Титов
C++ CoreHard Autumn 2018. Знай свое "железо": иерархия памяти - Александр ТитовC++ CoreHard Autumn 2018. Знай свое "железо": иерархия памяти - Александр Титов
C++ CoreHard Autumn 2018. Знай свое "железо": иерархия памяти - Александр Титов
 
C++ CoreHard Autumn 2018. Информационная безопасность и разработка ПО - Евген...
C++ CoreHard Autumn 2018. Информационная безопасность и разработка ПО - Евген...C++ CoreHard Autumn 2018. Информационная безопасность и разработка ПО - Евген...
C++ CoreHard Autumn 2018. Информационная безопасность и разработка ПО - Евген...
 
C++ CoreHard Autumn 2018. Заглядываем под капот «Поясов по C++» - Илья Шишков
C++ CoreHard Autumn 2018. Заглядываем под капот «Поясов по C++» - Илья ШишковC++ CoreHard Autumn 2018. Заглядываем под капот «Поясов по C++» - Илья Шишков
C++ CoreHard Autumn 2018. Заглядываем под капот «Поясов по C++» - Илья Шишков
 
C++ CoreHard Autumn 2018. Ускорение сборки C++ проектов, способы и последстви...
C++ CoreHard Autumn 2018. Ускорение сборки C++ проектов, способы и последстви...C++ CoreHard Autumn 2018. Ускорение сборки C++ проектов, способы и последстви...
C++ CoreHard Autumn 2018. Ускорение сборки C++ проектов, способы и последстви...
 
C++ CoreHard Autumn 2018. Метаклассы: воплощаем мечты в реальность - Сергей С...
C++ CoreHard Autumn 2018. Метаклассы: воплощаем мечты в реальность - Сергей С...C++ CoreHard Autumn 2018. Метаклассы: воплощаем мечты в реальность - Сергей С...
C++ CoreHard Autumn 2018. Метаклассы: воплощаем мечты в реальность - Сергей С...
 
C++ CoreHard Autumn 2018. Что не умеет оптимизировать компилятор - Александр ...
C++ CoreHard Autumn 2018. Что не умеет оптимизировать компилятор - Александр ...C++ CoreHard Autumn 2018. Что не умеет оптимизировать компилятор - Александр ...
C++ CoreHard Autumn 2018. Что не умеет оптимизировать компилятор - Александр ...
 
C++ CoreHard Autumn 2018. Кодогенерация C++ кроссплатформенно. Продолжение - ...
C++ CoreHard Autumn 2018. Кодогенерация C++ кроссплатформенно. Продолжение - ...C++ CoreHard Autumn 2018. Кодогенерация C++ кроссплатформенно. Продолжение - ...
C++ CoreHard Autumn 2018. Кодогенерация C++ кроссплатформенно. Продолжение - ...
 
C++ CoreHard Autumn 2018. Concurrency and Parallelism in C++17 and C++20/23 -...
C++ CoreHard Autumn 2018. Concurrency and Parallelism in C++17 and C++20/23 -...C++ CoreHard Autumn 2018. Concurrency and Parallelism in C++17 and C++20/23 -...
C++ CoreHard Autumn 2018. Concurrency and Parallelism in C++17 and C++20/23 -...
 
C++ CoreHard Autumn 2018. Обработка списков на C++ в функциональном стиле - В...
C++ CoreHard Autumn 2018. Обработка списков на C++ в функциональном стиле - В...C++ CoreHard Autumn 2018. Обработка списков на C++ в функциональном стиле - В...
C++ CoreHard Autumn 2018. Обработка списков на C++ в функциональном стиле - В...
 
C++ Corehard Autumn 2018. Обучаем на Python, применяем на C++ - Павел Филонов
C++ Corehard Autumn 2018. Обучаем на Python, применяем на C++ - Павел ФилоновC++ Corehard Autumn 2018. Обучаем на Python, применяем на C++ - Павел Филонов
C++ Corehard Autumn 2018. Обучаем на Python, применяем на C++ - Павел Филонов
 
C++ CoreHard Autumn 2018. Asynchronous programming with ranges - Ivan Čukić
C++ CoreHard Autumn 2018. Asynchronous programming with ranges - Ivan ČukićC++ CoreHard Autumn 2018. Asynchronous programming with ranges - Ivan Čukić
C++ CoreHard Autumn 2018. Asynchronous programming with ranges - Ivan Čukić
 
C++ CoreHard Autumn 2018. Debug C++ Without Running - Anastasia Kazakova
C++ CoreHard Autumn 2018. Debug C++ Without Running - Anastasia KazakovaC++ CoreHard Autumn 2018. Debug C++ Without Running - Anastasia Kazakova
C++ CoreHard Autumn 2018. Debug C++ Without Running - Anastasia Kazakova
 
C++ CoreHard Autumn 2018. Полезный constexpr - Антон Полухин
C++ CoreHard Autumn 2018. Полезный constexpr - Антон ПолухинC++ CoreHard Autumn 2018. Полезный constexpr - Антон Полухин
C++ CoreHard Autumn 2018. Полезный constexpr - Антон Полухин
 
C++ CoreHard Autumn 2018. Text Formatting For a Future Range-Based Standard L...
C++ CoreHard Autumn 2018. Text Formatting For a Future Range-Based Standard L...C++ CoreHard Autumn 2018. Text Formatting For a Future Range-Based Standard L...
C++ CoreHard Autumn 2018. Text Formatting For a Future Range-Based Standard L...
 
Исключительная модель памяти. Алексей Ткаченко ➠ CoreHard Autumn 2019
Исключительная модель памяти. Алексей Ткаченко ➠ CoreHard Autumn 2019Исключительная модель памяти. Алексей Ткаченко ➠ CoreHard Autumn 2019
Исключительная модель памяти. Алексей Ткаченко ➠ CoreHard Autumn 2019
 
Как помочь и как помешать компилятору. Андрей Олейников ➠ CoreHard Autumn 2019
Как помочь и как помешать компилятору. Андрей Олейников ➠  CoreHard Autumn 2019Как помочь и как помешать компилятору. Андрей Олейников ➠  CoreHard Autumn 2019
Как помочь и как помешать компилятору. Андрей Олейников ➠ CoreHard Autumn 2019
 
Автоматизируй это. Кирилл Тихонов ➠ CoreHard Autumn 2019
Автоматизируй это. Кирилл Тихонов ➠  CoreHard Autumn 2019Автоматизируй это. Кирилл Тихонов ➠  CoreHard Autumn 2019
Автоматизируй это. Кирилл Тихонов ➠ CoreHard Autumn 2019
 
Статичный SQL в С++14. Евгений Захаров ➠ CoreHard Autumn 2019
Статичный SQL в С++14. Евгений Захаров ➠  CoreHard Autumn 2019Статичный SQL в С++14. Евгений Захаров ➠  CoreHard Autumn 2019
Статичный SQL в С++14. Евгений Захаров ➠ CoreHard Autumn 2019
 

модель акторов и C++ что, зачем и как ?

  • 1. Модель Акторов и C++: что, зачем и как? Евгений Охотников
  • 2. О чем пойдет речь? Многопоточность и parallel concurrent computing. Модель Акторов в двух-трех-четырех-...-двенадцати слайдах. Сегодняшние иконы "Модели Акторов". Все две штуки. А как же C++ (пока его еще не закопали)? NIH*-синдром или что есть готового для C++? 2* NIH - Not Invented Here
  • 3. Многопоточность – это... инструмент, который активно применяется в двух очень разных областях: ● parallel computing (одновременно выполняются одинаковые операции над разными наборами однотипных данных); ● concurrent computing (одновременно выполняются совсем разные операции, возможно, над совершенно разными данными). Concurrent computing может быть и без многопоточности. Но на базе многопоточности concurrent computing доставляет больше всего... 3
  • 4. Далее только о многопоточности... ...применительно к concurrent computing. Именно здесь Модель Акторов оказывается очень удобной. А для parallel computing используются другие подходы и другие инструменты... 4
  • 5. Итак, многопоточность – это сложно Таки да, это сложно. Даже имея 20 лет опыта. Но почему? 5
  • 6. Изменяемое разделяемое состояние Именно изменяемое разделяемое состояние является одним из главных факторов сложности в многопоточном программировании. 6
  • 8. Убрать разделяемое состояние Ничего не разделяем. Ни за что не боремся. Пусть каждый поток владеет своими собственными данными. И никто кроме потока-владельца не имеет к этим данным доступа. Принцип shared nothing* (широко известен в узких кругах). 8* https://en.wikipedia.org/wiki/Shared_nothing_architecture
  • 9. Убрать разделяемое состояние Но что делать, если потоку X потребовалась какая-то информация, которая есть у потока Y? Что делать, если поток Y хочет, чтобы поток Z обновил какие-то данные у себя? 9
  • 10. Потокам нужно общаться, но как? Кажется, что есть два способа: 1. Синхронно. 2. Асинхронно. Но это только кажется... 10
  • 11. На самом-то деле... ...никакой синхронности, только хардкор асинхронное взаимодействие. Например, на основе отсылки и приема сообщений: ● поток X отсылает сообщение-запрос потоку Y; ● поток Y когда-то получит запрос потока X, обработает запрос и отошлет потоку X ответ; ● поток Y отсылает сообщение-обновление потоку Z; ● поток Z когда-то получит сообщение-обновление от потока Y и обновит те данные, которые принадлежат потоку Z. 11
  • 12. Просто же! Есть потоки. У каждого есть очередь входящих сообщений. Поток спит, если очередь входящих сообщений пуста. Поток просыпается, когда для него появляются входящие сообщения. Если потоку X нужно что-то от потока Y, то X отсылает сообщение в очередь входящих сообщений потока Y. Если поток Y хочет ответить потоку X, то Y отсылает сообщение в очередь входящих сообщений потока X. 12
  • 13. А если сообщения несут копию данных... ...то мы получаем очень приятный бонус: прозрачный переход к распределенности. Если поток Y передал в сообщении Msg копию данных, а не ссылку на них, то уже не суть важно, пойдет ли сообщение Msg в локальную очередь входящих сообщений потока Z. Или же в очередь исходящих данных для передачи на другой хост. Сообщение самодостаточно. Поэтому может быть сериализовано, передано по сети, десериализовано и обработано. 13
  • 14. Вот и весь фокус :) Модель акторов именно про это. Про изолированные потоки управления. И про их взаимодействие на основе обмена сообщениями. 14
  • 15. Модель Акторов Появилась в 1973-ем году благодаря работам Карла Хьюитта (Carl Hewitt). Была затем развита в 1981-ом Уильямом Клингером (William Clinger). И в 1985-ом Гулом Агха (Gul Agha). Это если говорить про формализацию Модели Акторов. Неформально она открывалась и переоткрывалась множество раз. 15
  • 16. Модель Акторов Отправные точки для желающих погрузиться в формальную теорию Модели Акторов: https://en.wikipedia.org/wiki/History_of_the_Actor_model https://en.wikipedia.org/wiki/Actor_model https://en.wikipedia.org/wiki/Actor_model_theory 16
  • 17. Модель Акторов. Основные принципы ● актор – это некая сущность, обладающая поведением; ● акторы реагируют на входящие сообщения; ● получив сообщение актор может: ○ отослать некоторое (конечное) количество сообщений другим акторам; ○ создать некоторое (конечное) количество новых акторов; ○ определить для себя новое поведение для обработки последующих сообщений. 17
  • 18. Актор – это некоторая сущность Не более того. Актором может быть отдельный процесс. Например, Erlang. Актором может быть отдельный поток (OS thread, "green" thread, fiber, ...). Например, goroutine в Go может рассматриваться как актор. Актором может быть объект, которому кто-то выделяет рабочий контекст. Например, Akka. 18
  • 19. Еще раз: актор – это некоторая сущность Модель Акторов не требует, чтобы актор был процессом или потоком, или конечным автоматом, или чем-то еще. Поэтому существующие и востребованные на практике реализации Модели Акторов очень сильно отличаются друг от друга. 19
  • 20. Модели Акторов уже более 40 лет За это время Модель Акторов пережила несколько волн популярности и забвения* Сейчас очередная волна популярности. Она началась где-то около 10-12 лет назад. Основным двигателем интереса стали Erlang, а затем Akka. 20* Why has the actor model not succeeded?
  • 21. Современные иконы: Erlang Пожалуй, самая известная реализация – язык Erlang* http://www.erlang.org/ Не только сам язык, но и Erlang VM, и OTP, и вообще все, что понастроили вокруг. 21* Я не встречал, чтобы Джо Армстронг говорил, что на Erlang повлияла Модель Акторов
  • 22. Современные иконы: Erlang Зародился в одной из исследовательских лабораторий Ericsson-а в 1986-ом году благодаря Джо Армстронгу (Joe Armstrong). В 1995-ом году после закрытия неудачного проекта AXE-N (на C++, кстати) был выбран в качестве основного языка для проекта AXD. Результатом стал успешный программно-аппаратный продукт AXD301 в котором было более миллиона строк на Erlang. 22
  • 23. Современные иконы: Erlang В конце 1990-х использование Erlang-а для новых проектов в Ericsson Radio AB было запрещено. Джо Армстронг покинул Ericsson. Erlang ушел в OpenSource. Erlang доказал свою состоятельность вне Ericsson-а. Ericsson одумался. В 2004-ом году Джо Армстронг возвратился в Ericsson. 23
  • 24. Современные иконы: Erlang За последние годы Erlang многократно показывал себя с лучшей стороны в очень серьезных проектах (например, WhatsApp использует Erlang). Многие компании убедившись в достоинствах Erlang-а задействуют Erlang в своих разработках. Из близких нам примеров: Wargaming. 24
  • 25. Современные иконы: Erlang -module(tut15). -export([start/0, ping/2, pong/0]). ping(0, Pong_PID) -> Pong_PID ! finished, io:format("ping finished~n", []); ping(N, Pong_PID) -> Pong_PID ! {ping, self()}, receive pong -> io:format("Ping received pong~n", []) end, ping(N - 1, Pong_PID). 25 pong() -> receive finished -> io:format("Pong finished~n", []); {ping, Ping_PID} -> io:format("Pong received ping~n", []), Ping_PID ! pong, pong() end. start() -> Pong_PID = spawn(tut15, pong, []), spawn(tut15, ping, [3, Pong_PID]).
  • 26. Современные иконы: Akka Фреймворк для Java и Scala. http://akka.io/ История началась в 2006: Филипп Холлер (Philipp Haller) разработал реализацию Модели Акторов для стандартной библиотеки языка Scala. В 2008-ом Джонас Бонер (Jonas Bonér) начал делать Erlang-овский OTP для Scala на базе акторов из Scala-stdlib*. Первая публичная версия Akka вышла в 2010-ом. 26* http://www.lightbend.com/akka-five-year-anniversary
  • 27. Современные иконы: Akka Очень популярна в JVM-мире. Соответственно, находит широкое применение там, где позиции JVM традиционно сильны: Web, онлайн-сервисы и суровый энтерпрайз... Яркие примеры: LinkedIn и Twitter. Стоящие за Akka люди так же причастны к таким современным buzz-word-ам, как Reactive Manifesto* и Microservices** :) 27 * http://www.reactivemanifesto.org/ ** https://en.wikipedia.org/wiki/Microservices
  • 28. Современные иконы: Akka import akka.actor._ case object PingMessage case object PongMessage case object StartMessage case object StopMessage class Ping(pong: ActorRef) extends Actor { var count = 0 def incrementAndPrint { count += 1; println("ping") } def receive = { case StartMessage => incrementAndPrint pong ! PingMessage case PongMessage => incrementAndPrint if (count > 99) { sender ! StopMessage println("ping stopped") context.stop(self) } else { sender ! PingMessage } 28 } } class Pong extends Actor { def receive = { case PingMessage => println(" pong") sender ! PongMessage case StopMessage => println("pong stopped") context.stop(self) } } object PingPongTest extends App { val system = ActorSystem("PingPongSystem") val pong = system.actorOf(Props[Pong], name = "pong") val ping = system.actorOf(Props(new Ping(pong)), name = "ping") // start them going ping ! StartMessage } http://alvinalexander.com/scala/scala-akka-actors-ping-pong-simple-example
  • 29. В чем сила, брат? Что же такое предлагают своим пользователям Erlang и Akka? Почему они востребованы и используются в очень серьезных проектах? 29
  • 30. Вот в чем: 1. Простота. Отсутствие разделяемых данных и взаимодействие посредством асинхронных сообщений спасают от ужасов программирования на мьютексах. 2. Масштабирование. Акторов может быть хоть миллион. Даже самую мелкую задачку можно поручить отдельному актору. Акторов можно распределять по нескольким процессам и нескольким нодам, при асинхронном обмене сообщениями это не суть важно. 3. Отказоустойчивость. Какие-то акторы могут "падать", другие акторы это обнаружат и исправят (см. систему супервизоров Erlang-а*). Shared nothing + message-passing сильно помогают и тут. 30* http://erlang.org/doc/man/supervisor.html
  • 31. Так говорил Джо Армстронг I also suspect that the advent of true parallel CPU cores will make programming parallel systems using conventional mutexes and shared data structures almost impossibly difficult, and that the pure message-passing systems will become the dominant way to program parallel systems. Так же я подозреваю, что пришествие настоящих многоядерных CPU сделает программирование параллельных систем с использованием традиционных мьютексов и разделяемых структур данных сложным до невозможности, и что именно обмен сообщениями станет доминирующим способом разработки параллельных систем. Disclaimer: перевод приблизительный, но основной смысл передан верно. 31A History of Erlang, Joe Armstrong, 2007.
  • 32. Кстати об отказоустойчивости Erlang и Java/Scala (речь об Akka) – это безопасные языки, работающие в управляемых средах (Erlang VM и JVM). На отказоустойчивость это влияет самым непосредственным образом. Деление на ноль в одном из процессов внутри Erlang VM и деление на ноль в одном из потоков большого приложения на C++ – это две большие разницы. 32
  • 33. А что с C++? Есть ли смысл в использовании Модели Акторов в C++? 33
  • 34. Неверный вопрос! Начинать нужно с более важного вопроса: А нужен ли вообще C++? 34
  • 35. Серьезно? И это на CoreHard C++? Таки да :( 35
  • 36. Так нужен ли вообще C++? С++ старый язык (более 30 лет с публичного релиза). За это время стал настоящим монстром, стандарт которого насчитывает ~1500 страниц. И это еще C++17 не приняли... Вобрал в себя множество нового (в переводе на русский: стал еще сложнее). Сохранил при этом совместимость с еще более древним языком С. Так что с отстрелом конечностей все в порядке. Каждый большой проект использует собственное подмножество C++. Огромное количество копролитов мамонта легаси кода. 36
  • 37. Тем не менее... ...какой еще мейнстримовый нативный язык без GC: ● настолько же быстр и эффективен? ● позволяет работать на самом низком уровне? ● позволяет подниматься на высокие уровни абстракции (ООП, обобщенное программирование, метапрограммирование)? ● снабжен таким же количеством разнообразного инструментария? ● так же хорошо и досконально описан в огромном количестве книг, статей, руководств, рекомендаций и пр.? ● обладает таким же большим коммьюнити? Если объективно посмотреть по сторонам, то альтернатив не так уж и много. 37
  • 38. Вывод прост: нужен, однозначно! А раз нужен, то нужны и инструменты, облегчающие жизнь C++ разработчикам. В том числе и реализации Модели Акторов для C++. 38
  • 39. Больше фреймворков, хороших и разных! Более-менее актуальный список инструментов для C++ можно найти здесь: https://en.wikipedia.org/wiki/Actor_model#Actor_libraries_and_frameworks Там не все. А часть того, что есть, уже умерло. Но все-таки. 39
  • 40. Четверо смелых для беглого знакомства Далее быстрый забег "по верхам" для знакомства с четырьмя C++ фреймворками, которые: ● на C++; ● подают признаки жизни (что уже не мало, на самом-то деле); ● кросс-платформенны; ● интересны с той или иной стороны. Есть еще, например, OOSMOS* и Asyncronous Agents Library** от MS, но они не вошли в обзор из-за нарушения каких-то из перечисленных выше пунктов. 40 * http://www.oosmos.com/ ** https://msdn.microsoft.com/en-us/library/dd492627.aspx
  • 41. QP/C++ http://www.state-machine.com/qpcpp/ C++98/03. Предназначен для разработки встраиваемого ПО. В том числе и для работы на голом железе. Двойная лицензия. Более 15 лет развития и эксплуатации. Декларируется приличный уровень соответствия MISRA C++2008. 41
  • 42. QP/C++ Акторы в QP/C++ – это иерархические конечные автоматы. Называются активными объектами. Код активных объектов можно писать обычным образом. Т.е. вручную набирать код C++ классов, методов и вот это вот все. А можно "нарисовать" активный объект в специальном визуальном инструменте для проектирования и C++ код будет сгенерирован. Контекст для работы активных объектов предоставляет QP. В зависимости от окружения активные объекты могут работать на отдельных нитях. А могут и сообща на одной-единственной. 42
  • 43. QP/C++ (пример кода: blinky.h) #ifndef blinky_h #define blinky_h using namespace QP; enum BlinkySignals { DUMMY_SIG = Q_USER_SIG, MAX_PUB_SIG, // the last published signal TIMEOUT_SIG, MAX_SIG // the last signal }; extern QMActive * const AO_Blinky; // opaque pointer #endif // blinky_h 43
  • 44. QP/C++ (пример кода: main.cpp) #include "qpcpp.h" #include "bsp.h" #include "blinky.h" int main() { static QEvt const *blinkyQSto[10]; // Event queue storage for Blinky BSP_init(); // initialize the Board Support Package QF::init(); // initialize the framework and the underlying RT kernel // instantiate and start the active objects... AO_Blinky->start(1U, // priority blinkyQSto, Q_DIM(blinkyQSto), // event queue (void *)0, 0U); // stack (unused) return QF::run(); // run the QF application } 44
  • 45. QP/C++ (пример кода: blinky.cpp, 1) #include "qpcpp.h" #include "bsp.h" #include "blinky.h" class Blinky : public QActive { private: QTimeEvt m_timeEvt; public: Blinky(); protected: static QState initial(Blinky * const me, QEvt const * const e); static QState off(Blinky * const me, QEvt const * const e); static QState on(Blinky * const me, QEvt const * const e); }; Blinky l_blinky; QMActive * const AO_Blinky = &l_blinky; // opaque pointer 45
  • 46. QP/C++ (пример кода: blinky.cpp, 2) Blinky::Blinky() : QActive(Q_STATE_CAST(&Blinky::initial)), m_timeEvt(this, TIMEOUT_SIG, 0U) {} QState Blinky::initial(Blinky * const me, QEvt const * const e) { (void)e; // unused parameter // arm the time event to expire in half a second and every half second me->m_timeEvt.armX(BSP_TICKS_PER_SEC/2U, BSP_TICKS_PER_SEC/2U); return Q_TRAN(&Blinky::off); } 46
  • 47. QP/C++ (пример кода: blinky.cpp, 3) QState Blinky::off(Blinky * const me, QEvt const * const e) { QState status; switch (e->sig) { case Q_ENTRY_SIG: { BSP_ledOff(); status = Q_HANDLED(); break; } case TIMEOUT_SIG: { status = Q_TRAN(&Blinky::on); break; } default: { status = Q_SUPER(&QHsm::top); break; } } return status; } 47 QState Blinky::on(Blinky * const me, QEvt const * const e) { QState status; switch (e->sig) { case Q_ENTRY_SIG: { BSP_ledOn(); status = Q_HANDLED(); break; } case TIMEOUT_SIG: { status = Q_TRAN(&Blinky::off); break; } default: { status = Q_SUPER(&QHsm::top); break; } } return status; }
  • 48. Just::Thread Pro: Actors Edition http://www.stdthread.co.uk/pro/ C++11. Платная библиотека. Автор – Энтони Уильямс (Anthony Williams). Он же написал книгу "C++ Concurrency in Action". На этом, пожалуй, достоинства заканчиваются :) Под каждого актора выделяется отдельный поток ОС. 48
  • 49. Just::Thread Pro: Actors Edition (ping-pong) #include <jss/actor.hpp> #include <iostream> #include <thread> int main() { struct pingpong { jss::actor_ref sender; pingpong(jss::actor_ref sender_): sender(sender_) {} }; jss::actor pp1( []{ for(;;) { jss::actor::receive().match<pingpong>( [](pingpong p){ std::cout<<"pingn"; p.sender.send(pingpong(jss::actor::self())); }); } }); 49 jss::actor pp2( []{ for(;;) { jss::actor::receive().match<pingpong>( [](pingpong p){ std::cout<<"pongn"; p.sender.send(pingpong(jss::actor::self())); }); } }); pp1.send(pingpong(pp2)); std::this_thread::sleep_for(std::chrono::seconds(2)); pp1.stop(); pp2.stop(); }
  • 50. C++ Actor Framework (он же CAF) http://www.actor-framework.org/ C++11 и выше (чем выше, тем лучше). OpenSource под BSD-3-CLAUSE лицензией. Самая распиаренная реализация Модели Акторов для C++. Позиционирует себя как очень быстрый фреймворк. Не то, чтобы так уж заслуженно* ;) Пока еще не стабилизировался. 50* Performance Comparison SO-5.5.15.2 vs CAF-0.14.4
  • 51. C++ Actor Framework (он же CAF) Изначально копировал Erlang в C++ настолько близко, насколько это возможно. Постепенно видоизменяется и приобретает свои уникальные черты. Ценой за мимикрию под Erlang являются высокие требования CAF-а к уровню поддержки стандартов в C++ в компиляторе. Официальная поддержка Windows/VC++ появилась только после выхода Visual Studio 2015 update 3. Есть поддержка распределенности. Собственный протокол с реализацией на базе Boost::Asio. 51
  • 52. C++ Actor Framework (fixed_stack, 1) #include <cassert> #include <cstdint> #include <iostream> #include "caf/all.hpp" using std::endl; using namespace caf; namespace { using pop_atom = atom_constant<atom("pop")>; using push_atom = atom_constant<atom("push")>; enum class fixed_stack_errc : uint8_t { push_to_full = 1, pop_from_empty }; error make_error(fixed_stack_errc x) { return error{static_cast<uint8_t>(x), atom("FixedStack")}; } 52
  • 53. C++ Actor Framework (fixed_stack, 2) class fixed_stack : public event_based_actor { public: fixed_stack(actor_config& cfg, size_t stack_size) : event_based_actor(cfg), size_(stack_size) { full_.assign( [=](push_atom, int) -> error { return fixed_stack_errc::push_to_full; }, [=](pop_atom) -> int { auto result = data_.back(); data_.pop_back(); become(filled_); return result; } ); 53
  • 54. C++ Actor Framework (fixed_stack, 3) filled_.assign( [=](push_atom, int what) { data_.push_back(what); if (data_.size() == size_) become(full_); }, [=](pop_atom) -> int { auto result = data_.back(); data_.pop_back(); if (data_.empty()) become(empty_); return result; } ); 54
  • 55. C++ Actor Framework (fixed_stack, 4) empty_.assign( [=](push_atom, int what) { data_.push_back(what); become(filled_); }, [=](pop_atom) -> error { return fixed_stack_errc::pop_from_empty; } ); } 55
  • 56. C++ Actor Framework (fixed_stack, 5) behavior make_behavior() override { assert(size_ < 2); return empty_; } private: size_t size_; std::vector<int> data_; behavior full_; behavior filled_; behavior empty_; }; 56
  • 57. C++ Actor Framework (fixed_stack, 6) void caf_main(actor_system& system) { scoped_actor self{system}; auto st = self->spawn<fixed_stack>(5u); // fill stack for (int i = 0; i < 10; ++i) self->send(st, push_atom::value, i); // drain stack aout(self) << "stack: { "; bool stack_empty = false; while (!stack_empty) { self->request(st, std::chrono::seconds(10), pop_atom::value).receive( [&](int x) { aout(self) << x << " "; }, [&](const error&) { stack_empty = true; } ); } aout(self) << "}" << endl; self->send_exit(st, exit_reason::user_shutdown); } } // namespace <anonymous> CAF_MAIN() 57
  • 58. SObjectizer-5 https://sourceforge.net/projects/sobjectizer/ или https://github.com/eao197/so-5-5 C++11 (минимальные требования к компилятору: GCC 4.8, MSVC++12.0). OpenSource под BSD-3-CLAUSE лицензией. С очень долгой историей: 1995-2000: Гомель, КБ Системного Программирования, проект SCADA Objectizer; 2002-...: Гомель-Москва, Интервэйл, проект SObjectizer-4; 2010-...: Гомель-Москва, Интервэйл, The SObjectizer Team, проект SObjectizer-5. 58
  • 59. SObjectizer-5 SO-4 в продакшене c 2002-го года. И до сих пор работает. SO-5 в продакшене с 2011-го года. Обратная совместимость – must have. Без фанатизма, но позволить себе вносить ломающие совместимость изменения в каждый релиз мы не можем. От слова совсем. Версия SO-5.5.0 вышла в октябре 2014-го. С тех пор в ветке 5.5.* нет ломающих изменений. Последняя стабильная версия 5.5.18 – сентябрь 2016. 59
  • 60. SObjectizer-5 Акторы в SO-5 называются агентами. Так сложилось. Агенты в SO-5 – это иерархические конечные автоматы (вложенные состояния, обработчики входа-выхода, история, временные лимиты). Рабочий контекст агентам предоставляют диспетчеры. Разработчику "из коробки" доступно восемь типов готовых диспетчеров. Распределенность в SO-5 не поддерживается. Был опыт в SO-4. Поэтому в SO-5 решили обходиться готовыми сторонними инструментами по задачу (MQTT, AMQP, HTTP и т.д.). 60
  • 61. SObjectizer-5 Главное отличие от прочих фреймворков: SO-5 – это симбиоз Модели Акторов, модели Publish/Subscribe. С элементами CSP* Сообщения отсылаются не агенту, а в message box (mbox). За mbox-ом может быть один агент, может быть множество агентов. Или ни одного. Mbox является аналогом Topic-а из Pub/Sub. Отсылка сообщения – аналогом Publish-а из Pub/Sub. И, как и в Pub/Sub, агент должен подписаться на сообщение, чтобы получить его. 61* https://en.wikipedia.org/wiki/Communicating_sequential_processes
  • 62. SObjectizer-5 (blinking_led, 1) #include <iostream> #include <so_5/all.hpp> class blinking_led final : public so_5::agent_t { state_t off{ this }, blinking{ this }, blink_on{ initial_substate_of{ blinking } }, blink_off{ substate_of{ blinking } }; public : struct turn_on_off : public so_5::signal_t {}; 62
  • 63. SObjectizer-5 (blinking_led, 2) blinking_led( context_t ctx ) : so_5::agent_t{ ctx } { this >>= off; off.just_switch_to< turn_on_off >( blinking ); blinking.just_switch_to< turn_on_off >( off ); blink_on .on_enter( []{ std::cout << "ON" << std::endl; } ) .on_exit( []{ std::cout << "off" << std::endl; } ) .time_limit( std::chrono::milliseconds{1250}, blink_off ); blink_off .time_limit( std::chrono::milliseconds{750}, blink_on ); } }; 63
  • 64. SObjectizer-5 (blinking_led, 3) int main() { so_5::launch( []( so_5::environment_t & env ) { so_5::mbox_t m; env.introduce_coop( [&]( so_5::coop_t & coop ) { auto led = coop.make_agent< blinking_led >(); m = led->so_direct_mbox(); } ); auto pause = []( unsigned int v ) { std::this_thread::sleep_for( std::chrono::seconds{v} ); }; so_5::send< blinking_led::turn_on_off >( m ); pause( 10 ); so_5::send< blinking_led::turn_on_off >( m ); pause( 5 ); so_5::send< blinking_led::turn_on_off >( m ); pause( 5 ); env.stop(); } ); } 64
  • 65. Заключение 1/3 Модель Акторов – это очень удобный инструмент в случаях, где использование этой модели уместно1 . Это уже неоднократно доказывалось успешным применением таких инструментов, как Erlang и Akka в самых разнообразных проектах. Да и вообще за асинхронным обменом сообщений между независимыми сущностями будущее. Прислушайтесь к Джо Армстронгу, он плохого не посоветует ;) 1) Не верьте рекламе: уместно не везде. 65
  • 66. Заключение 2/3 Наш опыт показывает, что при наличии подходящих инструментов Модель Акторов имеет смысл применять и в C++. При этом для C++ подходящие готовые инструменты уже есть. На разный вкус и цвет. И размер кошелька, конечно же. В коммерческом проекте за QP/C++ и за Just::Thread Pro придется заплатить. За SObjectizer и CAF – нет. По крайней мере сразу не придется. 66
  • 67. Заключение 3/3 Вот чего делать не стоит, так это браться за написание собственного акторного фреймворка. Неблагодарное это дело. Проверено. На людях. Лучше все-таки взять что-то готовое. Hint: купляйце беларускае. И пусть кто-нибудь другой весело бегает по граблям многопоточности :) 67
  • 69. Bonus track (SO-5's fixed_stack, 1) #include <iostream> #include <so_5/all.hpp> class fixed_stack final : public so_5::agent_t { state_t st_empty{ this }, st_filled{ this }, st_full{ this }; const size_t m_max_size; std::vector< int > m_stack; public : class empty_stack final : public std::logic_error { public : using std::logic_error::logic_error; }; struct push { int m_val; }; struct pop : public so_5::signal_t {}; 69* https://bitbucket.org/sobjectizerteam/fixed_stack_example
  • 70. Bonus track (SO-5's fixed_stack, 2) fixed_stack( context_t ctx, size_t max_size ) : so_5::agent_t( ctx ) , m_max_size( max_size ) { this >>= st_empty; so_subscribe_self() .in( st_empty ) .in( st_filled ) .event( &fixed_stack::on_push ); so_subscribe_self() .in( st_filled ) .in( st_full ) .event( &fixed_stack::on_pop_when_not_empty ); so_subscribe_self() .in( st_empty ) .event( &fixed_stack::on_pop_when_empty ); } 70
  • 71. Bonus track (SO-5's fixed_stack, 3) private : void on_push( const push & w ) { m_stack.push_back( w.m_val ); this >>= ( m_stack.size() == m_max_size ? st_full : st_filled ); } int on_pop_when_not_empty( mhood_t< pop > ) { auto r = m_stack.back(); m_stack.pop_back(); this >>= ( m_stack.empty() ? st_empty : st_filled ); return r; } int on_pop_when_empty( mhood_t< pop > ) { throw empty_stack( "empty_stack" ); } }; 71
  • 72. Bonus track (SO-5's fixed_stack, 4) int main() { try { so_5::launch( []( so_5::environment_t & env ) { so_5::mbox_t stack; env.introduce_coop( [&stack]( so_5::coop_t & coop ) { stack = coop.make_agent< fixed_stack >( 5u )->so_direct_mbox(); } ); for( int i = 0; i < 10; ++i ) so_5::send< fixed_stack::push >( stack, i ); std::cout << "stack { "; try { for(;;) std::cout << so_5::request_value< int, fixed_stack::pop >( stack, std::chrono::seconds(10) ) << " "; } catch( const fixed_stack::empty_stack & ) {} std::cout << "}" << std::endl; env.stop(); } ); return 0; } catch( const std::exception & x ) { std::cerr << "Oops! " << x.what() << std::endl; } return 2; } 72
  • 73. Документация по SObjectizer: https://sourceforge.net/p/sobjectizer/wiki/Home/ Серия статей о SObjectizer на русском: SObjectizer: что это, для чего это и почему это выглядит именно так? От простого к сложному: Часть I, Часть II, Часть III. Акторы в виде конечных автоматов – это плохо или хорошо? Проблема перегрузки агентов и средства борьбы с ней. Нежная дружба агентов и исключений. Серия презентаций о SObjectizer на английском "Dive into SObjectizer-5.5": Intro, Agent's States, More About Coops, Exceptions, Timers, Synchonous Interaction, Message Limits, Dispatchers, Message Chains. Блог автора доклада: eao197.blogspot.com О SObjectizer в блоге: eao197.blogspot.com/search/label/SObjectizer Почта автора доклада: eao197 на gmail тчк com 73