SlideShare a Scribd company logo
1 of 69
Download to read offline
C++ CoreHard Autumn 2018
Actors vs CSP vs Tasks...
Евгений Охотников
Коротко о себе
Профессиональный разработчик с 1994-го.
● 1994-2000: АСУ ТП/SCADA и т.п.;
● 2001-2014: телеком, платежные сервисы;
● 2014-...: OpenSource-инструментарий для C++.
Автор блога "Размышлизмы eao197" (http://eao197.blogspot.com/)
Сооснователь stiffstream.com ⇛ (SObjectizer, RESTinio)
Автор ряда докладов про Модель Акторов и С++.
2
Начнем с банальностей
Многопоточность – это зло
3
Не грех повторить еще раз:
Многопоточное программирование на
C++ посредством голых нитей, mutex-ов и
condition variables – это пот, боль и кровь.
4
Можно не верить мне...
https://habr.com/company/pixonic/blog/426875/
5
Архитектура мета-
сервера мобильного
онлайн-шутера
Tacticool
Можно не верить мне...
https://habr.com/company/pixonic/blog/426875/
6
Архитектура мета-
сервера мобильного
онлайн-шутера
Tacticool
Через пару недель, потраченных на
поиск и исправление наиболее
критических багов, мы решили, что
проще переписать все с нуля, чем
пытаться исправить все недостатки
текущего решения.
Почему мы ходим по граблям?
Незнание?
Лень?
NIH-синдром?
7
Есть много чего
Проверено временем и множеством проектов:
● actors
● communicating sequential processes (CSP)
● tasks (async, promises, futures, ...)
● data flows
● reactive programming
● ...
Этому вряд ли учат в ВУЗ-ах.
8
Простая задача
HTTP-сервер, который:
● принимает запрос (ID картинки, ID пользователя);
● отдает картинку с "водяными знаками", уникальными для этого
пользователя.
9
Что нужно делать?
10
client
our service
user database
image storage
Конкурентность напрашивается...
11
Набор рабочих нитей
12
Http Server
Request
Processing
Http Client
(outgoing
requests)
Image Processing
Disclaimer
Примеры не привязаны к какому-то конкретному инструменту.
Везде есть некий execution_context.
13
Попытка №1
Actors
14
Модель Акторов. Основные принципы
● актор – это некая сущность, обладающая поведением;
● акторы реагируют на входящие сообщения;
● получив сообщение актор может:
○ отослать некоторое (конечное) количество сообщений
другим акторам;
○ создать некоторое (конечное) количество новых акторов;
○ определить для себя новое поведение для обработки
последующих сообщений.
15
Модель Акторов. Основные принципы
● актор – это некая сущность, обладающая поведением;
● акторы реагируют на входящие сообщения;
● получив сообщение актор может:
○ отослать некоторое (конечное) количество сообщений
другим акторам;
○ создать некоторое (конечное) количество новых акторов;
○ определить для себя новое поведение для обработки
последующих сообщений.
16
Могут быть реализованы сильно по-разному:
● каждый актор – это отдельный поток ОС;
● каждый актор – это сопрограмма (stackful);
● каждый актор – это объект у которого кто-то
вызывает коллбэки.
Сейчас будем говорить про акторов виде объектов с
коллбэками.
Сопрограммы оставим для разговора про CSP.
Один из возможных вариантов
17
Актор request_handler (1)
class request_handler final : public some_basic_type {
const execution_context context_;
const request request_;
optional<user_info> user_info_;
optional<image_loaded> image_;
void on_start();
void on_user_info(user_info info);
void on_image_loaded(image_loaded image);
void on_mixed_image(mixed_image image);
void send_mix_images_request();
... // вся специфическая для фреймворка обвязка.
};
18
Актор request_handler (2)
void request_handler::on_start() {
send(context_.user_checker(), check_user{request_.user_id(), self()});
send(context_.image_downloader(), download_image{request_.image_id(), self()});
}
19
Актор request_handler (3)
void request_handler::on_user_info(user_info info) {
user_info_ = std::move(info);
if(image_)
send_mix_images_request();
}
void request_handler::on_image_loaded(image_loaded image) {
image_ = std::move(image);
if(user_info_)
send_mix_images_request();
}
20
Актор request_handler (4)
void request_handler::send_mix_images_request() {
send(context_.image_mixer(),
mix_images{user_info->watermark_image(), *image_, self()});
}
void request_handler::on_mixed_image(mixed_image image) {
send(context_.http_srv(), reply{..., std::move(image), ...});
}
21
Особенности Модели Акторов (1)
Акторы реактивны.
Работают при наличии входящих сообщений.
22
Особенности Модели Акторов (2)
Акторы подвержены перегрузкам.
Следствие асинхронной природы взаимодействия.
send не блокирует отправителя.
23
Особенности Модели Акторов (3)
Много акторов ≠ решение.
Зачастую много акторов ⇒ еще одна проблема.
24
Куда смотреть, что брать?
SObjectizer
https://stiffstream.com/en/products/sobjectizer.html
C++ Actor Framework (CAF)
http://actor-framework.org
QP/C++
https://www.state-machine.com/qpcpp/
https://en.wikipedia.org/wiki/Actor_model#Actor_libraries_and_frameworks
25
Поддержи отечественного
производителя!
Попытка №2
CSP
(communicating sequential processes)
26
CSP на пальцах и без матана
Композиция параллельно работающих последовательных
процессов.
Взаимодействие посредством асинхронных сообщений.
Сообщения доставляются посредством каналов.
У каналов есть две операции: write (send) и read (receive).
27
CSP на пальцах и без матана
28
Композиция параллельно работающих последовательных
процессов.
Взаимодействие посредством асинхронных сообщений.
Сообщения доставляются посредством каналов.
У каналов есть две операции: write (send) и read (receive).
"Последовательные процессы" внутри одного
процесса ОС могут быть реализованы как:
● отдельные нити ОС. В этом случае имеем
вытесняющую многозадачность;
● сопрограммы (stackful coroutines, green threads,
fibers, ...). В этом случае имеем кооперативную
многозадачность.
Один из возможных вариантов
29
"Процесс" request_handler
void request_handler(const execution_context ctx, const request req)
{
auto user_info_ch = make_chain<user_info>();
auto image_loaded_ch = make_chain<image_loaded>();
ctx.user_checker_ch().write(check_user{req.user_id(), user_info_ch});
ctx.image_downloader_ch().write(download_image{req.image_id(), image_loaded_ch});
auto user = user_info_ch.read();
auto original_image = image_loaded_ch.read();
auto image_mix_ch = make_chain<mixed_image>();
ctx.image_mixer_ch().write(
mix_image{user.watermark_image(), std::move(original_image), image_mix_ch});
auto result_image = image_mix_ch.read();
ctx.http_srv_ch().write(reply{..., std::move(result_image), ...});
}
30
"Процесс" request_handler
void request_handler(const execution_context ctx, const request req)
{
auto user_info_ch = make_chain<user_info>();
auto image_loaded_ch = make_chain<image_loaded>();
ctx.user_checker_ch().write(check_user{req.user_id(), user_info_ch});
ctx.image_downloader_ch().write(download_image{req.image_id(), image_loaded_ch});
auto user = user_info_ch.read();
auto original_image = image_loaded_ch.read();
auto image_mix_ch = make_chain<mixed_image>();
ctx.image_mixer_ch().write(
mix_image{user.watermark_image(), std::move(original_image), image_mix_ch});
auto result_image = image_mix_ch.read();
ctx.http_srv_ch().write(reply{..., std::move(result_image), ...});
}
31
"Процесс" request_handler
void request_handler(const execution_context ctx, const request req)
{
auto user_info_ch = make_chain<user_info>();
auto image_loaded_ch = make_chain<image_loaded>();
ctx.user_checker_ch().write(check_user{req.user_id(), user_info_ch});
ctx.image_downloader_ch().write(download_image{req.image_id(), image_loaded_ch});
auto user = user_info_ch.read();
auto original_image = image_loaded_ch.read();
auto image_mix_ch = make_chain<mixed_image>();
ctx.image_mixer_ch().write(
mix_image{user.watermark_image(), std::move(original_image), image_mix_ch});
auto result_image = image_mix_ch.read();
ctx.http_srv_ch().write(reply{..., std::move(result_image), ...});
}
32
"Процесс" request_handler
void request_handler(const execution_context ctx, const request req)
{
auto user_info_ch = make_chain<user_info>();
auto image_loaded_ch = make_chain<image_loaded>();
ctx.user_checker_ch().write(check_user{req.user_id(), user_info_ch});
ctx.image_downloader_ch().write(download_image{req.image_id(), image_loaded_ch});
auto user = user_info_ch.read();
auto original_image = image_loaded_ch.read();
auto image_mix_ch = make_chain<mixed_image>();
ctx.image_mixer_ch().write(
mix_image{user.watermark_image(), std::move(original_image), image_mix_ch});
auto result_image = image_mix_ch.read();
ctx.http_srv_ch().write(reply{..., std::move(result_image), ...});
}
33
"Процесс" request_handler
void request_handler(const execution_context ctx, const request req)
{
auto user_info_ch = make_chain<user_info>();
auto image_loaded_ch = make_chain<image_loaded>();
ctx.user_checker_ch().write(check_user{req.user_id(), user_info_ch});
ctx.image_downloader_ch().write(download_image{req.image_id(), image_loaded_ch});
auto user = user_info_ch.read();
auto original_image = image_loaded_ch.read();
auto image_mix_ch = make_chain<mixed_image>();
ctx.image_mixer_ch().write(
mix_image{user.watermark_image(), std::move(original_image), image_mix_ch});
auto result_image = image_mix_ch.read();
ctx.http_srv_ch().write(reply{..., std::move(result_image), ...});
}
34
"Процесс" request_handler
void request_handler(const execution_context ctx, const request req)
{
auto user_info_ch = make_chain<user_info>();
auto image_loaded_ch = make_chain<image_loaded>();
ctx.user_checker_ch().write(check_user{req.user_id(), user_info_ch});
ctx.image_downloader_ch().write(download_image{req.image_id(), image_loaded_ch});
auto user = user_info_ch.read();
auto original_image = image_loaded_ch.read();
auto image_mix_ch = make_chain<mixed_image>();
ctx.image_mixer_ch().write(
mix_image{user.watermark_image(), std::move(original_image), image_mix_ch});
auto result_image = image_mix_ch.read();
ctx.http_srv_ch().write(reply{..., std::move(result_image), ...});
}
35
"Процесс" request_handler
void request_handler(const execution_context ctx, const request req)
{
auto user_info_ch = make_chain<user_info>();
auto image_loaded_ch = make_chain<image_loaded>();
ctx.user_checker_ch().write(check_user{req.user_id(), user_info_ch});
ctx.image_downloader_ch().write(download_image{req.image_id(), image_loaded_ch});
auto user = user_info_ch.read();
auto original_image = image_loaded_ch.read();
auto image_mix_ch = make_chain<mixed_image>();
ctx.image_mixer_ch().write(
mix_image{user.watermark_image(), std::move(original_image), image_mix_ch});
auto result_image = image_mix_ch.read();
ctx.http_srv_ch().write(reply{..., std::move(result_image), ...});
}
36
"Процесс" request_handler
void request_handler(const execution_context ctx, const request req)
{
auto user_info_ch = make_chain<user_info>();
auto image_loaded_ch = make_chain<image_loaded>();
ctx.user_checker_ch().write(check_user{req.user_id(), user_info_ch});
ctx.image_downloader_ch().write(download_image{req.image_id(), image_loaded_ch});
auto user = user_info_ch.read();
auto original_image = image_loaded_ch.read();
auto image_mix_ch = make_chain<mixed_image>();
ctx.image_mixer_ch().write(
mix_image{user.watermark_image(), std::move(original_image), image_mix_ch});
auto result_image = image_mix_ch.read();
ctx.http_srv_ch().write(reply{..., std::move(result_image), ...});
}
37
Особенности CSP (1)
"Процессы" могут вести себя как захотят: быть реактивными,
проактивными или чередовать реактивность с проактивностью.
"Процессы" могут работать даже в отсутствии сообщений.
38
Особенности CSP (2)
"Родные" механизмы защиты от перегрузки.
Каналы могут быть ограничены по размеру.
Где-то только такими и могут быть.
Отправитель блокируется при записи в полный канал.
39
Особенности CSP (3)
"Процессы" в виде нитей ОС ⇒ дорого.
Плата за стек. Плата за переключение.
Но вытесняющая многозадачность.
"Процессы" в виде сопрограмм ⇒ дешево.
Но кооперативная многозадачность.
Но сюрпризы с 3rd-party libs (thread-local-storage, например).
40
Особенности CSP (4)
Много "процессов" ≠ решение.
Зачастую много "процессов" ⇒ еще одна проблема.
41
Куда смотреть, что брать?
Boost.Fiber
https://www.boost.org
SObjectizer
https://stiffstream.com/en/products/sobjectizer.html
42
Actors vs CSP
Actors:
один-единственный "канал",
только реактивность,
могут быть сложными конечными автоматами.
CSP-шные процессы:
много каналов,
и реактивность, и проактивность,
не очень хорошо с конечными автоматами,
лучше, когда поддерживаются на уровне языка и stdlib
43
Попытка №3
Tasks
(async, futures, then, wait_all, ...)
44
Про Task-based подход в двух словах
Решение строится как набор небольших задач.
Каждая задача выполняет одну операцию.
Задачи запускаются вызовами async. Результатом async является
future.
Задачи провязываются в "цепочки" посредством .then(), wait_all(),
wait_any().
45
Реализация обработки запроса (1)
void handle_request(const execution_context & ctx, request req)
{
auto user_info_ft = async(ctx.http_client_ctx(),
[req] { return retrieve_user_info(req.user_id()); });
auto original_image_ft = async(ctx.http_client_ctx(),
[req] { return download_image(req.image_id()); });
when_all(user_info_ft, original_image_ft).then(
[&ctx, req](tuple<future<user_info>, future<image_loaded>> data) {
async(ctx.image_mixer_ctx(), [&ctx, req, d=std::move(data)] {
return mix_image(get<0>(d).get().watermark_image(), get<1>(d).get());
})
.then([req](future<mixed_image> mixed) {
async(ctx.http_srv_ctx(), [req, im=std::move(mixed)] { make_reply(...); });
});
});
}
46
Реализация обработки запроса (2)
void handle_request(const execution_context & ctx, request req)
{
auto user_info_ft = async(ctx.http_client_ctx(),
[req] { return retrieve_user_info(req.user_id()); });
auto original_image_ft = async(ctx.http_client_ctx(),
[req] { return download_image(req.image_id()); });
when_all(user_info_ft, original_image_ft).then(
[&ctx, req](tuple<future<user_info>, future<image_loaded>> data) {
async(ctx.image_mixer_ctx(), [&ctx, req, d=std::move(data)] {
return mix_image(get<0>(d).get().watermark_image(), get<1>(d).get());
})
.then([req](future<mixed_image> mixed) {
async(ctx.http_srv_ctx(), [req, im=std::move(mixed)] { make_reply(...); });
});
});
}
47
Реализация обработки запроса (3)
void handle_request(const execution_context & ctx, request req)
{
auto user_info_ft = async(ctx.http_client_ctx(),
[req] { return retrieve_user_info(req.user_id()); });
auto original_image_ft = async(ctx.http_client_ctx(),
[req] { return download_image(req.image_id()); });
when_all(user_info_ft, original_image_ft).then(
[&ctx, req](tuple<future<user_info>, future<image_loaded>> data) {
async(ctx.image_mixer_ctx(), [&ctx, req, d=std::move(data)] {
return mix_image(get<0>(d).get().watermark_image(), get<1>(d).get());
})
.then([req](future<mixed_image> mixed) {
async(ctx.http_srv_ctx(), [req, im=std::move(mixed)] { make_reply(...); });
});
});
}
48
Реализация обработки запроса (4)
void handle_request(const execution_context & ctx, request req)
{
auto user_info_ft = async(ctx.http_client_ctx(),
[req] { return retrieve_user_info(req.user_id()); });
auto original_image_ft = async(ctx.http_client_ctx(),
[req] { return download_image(req.image_id()); });
when_all(user_info_ft, original_image_ft).then(
[&ctx, req](tuple<future<user_info>, future<image_loaded>> data) {
async(ctx.image_mixer_ctx(), [&ctx, req, d=std::move(data)] {
return mix_image(get<0>(d).get().watermark_image(), get<1>(d).get());
})
.then([req](future<mixed_image> mixed) {
async(ctx.http_srv_ctx(), [req, im=std::move(mixed)] { make_reply(...); });
});
});
}
49
Реализация обработки запроса (5)
void handle_request(const execution_context & ctx, request req)
{
auto user_info_ft = async(ctx.http_client_ctx(),
[req] { return retrieve_user_info(req.user_id()); });
auto original_image_ft = async(ctx.http_client_ctx(),
[req] { return download_image(req.image_id()); });
when_all(user_info_ft, original_image_ft).then(
[&ctx, req](tuple<future<user_info>, future<image_loaded>> data) {
async(ctx.image_mixer_ctx(), [&ctx, req, d=std::move(data)] {
return mix_image(get<0>(d).get().watermark_image(), get<1>(d).get());
})
.then([req](future<mixed_image> mixed) {
async(ctx.http_srv_ctx(), [req, im=std::move(mixed)] { make_reply(...); });
});
});
}
50
Реализация обработки запроса (6)
void handle_request(const execution_context & ctx, request req)
{
auto user_info_ft = async(ctx.http_client_ctx(),
[req] { return retrieve_user_info(req.user_id()); });
auto original_image_ft = async(ctx.http_client_ctx(),
[req] { return download_image(req.image_id()); });
when_all(user_info_ft, original_image_ft).then(
[&ctx, req](tuple<future<user_info>, future<image_loaded>> data) {
async(ctx.image_mixer_ctx(), [&ctx, req, d=std::move(data)] {
return mix_image(get<0>(d).get().watermark_image(), get<1>(d).get());
})
.then([req](future<mixed_image> mixed) {
async(ctx.http_srv_ctx(), [req, im=std::move(mixed)] { make_reply(...); });
});
});
}
51
Последовательность операций
void handle_request(const execution_context & ctx, request req)
{
auto user_info_ft = async(ctx.http_client_ctx(),
[req] { return retrieve_user_info(req.user_id()); });
auto original_image_ft = async(ctx.http_client_ctx(),
[req] { return download_image(req.image_id()); });
when_all(user_info_ft, original_image_ft).then(
[&ctx, req](tuple<future<user_info>, future<image_loaded>> data) {
async(ctx.image_mixer_ctx(), [&ctx, req, d=std::move(data)] {
return mix_image(get<0>(d).get().watermark_image(), get<1>(d).get());
})
.then([req](future<mixed_image> mixed) {
async(ctx.http_srv_ctx(), [req, im=std::move(mixed)] { make_reply(...); });
});
});
}
52
1
2
3
4
5
Последовательность операций
53
1
2
3
4
5
0
Загрузка user_info
Загрузка изображения
Последовательность операций
54
1
2
3
4
5
0
Загрузка user_info
Загрузка изображения
Есть и
изображение, и
user_info
Последовательность операций
55
1
2
3
4
5
0
Загрузка user_info
Загрузка изображения
Есть и
изображение, и
user_info
Микширование
изображения
Последовательность операций
56
1
2
3
4
5
0
Загрузка user_info
Загрузка изображения
Есть и
изображение, и
user_info
Микширование
изображения
Изображение
смикшировано
Последовательность операций
57
1
2
3
4
5
0
Загрузка user_info
Загрузка изображения
Есть и
изображение, и
user_info
Микширование
изображения
Изображение
смикшировано
Формирование
ответа на запрос
void handle_request(const execution_context & ctx, request req)
{
auto user_info_ft = async(ctx.http_client_ctx(),
[req] { return retrieve_user_info(req.user_id()); });
auto original_image_ft = async(ctx.http_client_ctx(),
[req] { return download_image(req.image_id()); });
when_all(user_info_ft, original_image_ft).then(
[&ctx, req](tuple<future<user_info>, future<image_loaded>> data) {
async(ctx.image_mixer_ctx(), [&ctx, req, d=std::move(data)] {
return mix_image(get<0>(d).get().watermark_image(), get<1>(d).get());
})
.then([req](future<mixed_image> mixed) {
async(ctx.http_srv_ctx(), [req, im=std::move(mixed)] { make_reply(...); });
});
});
}
Последовательность операций
58
1
2
3
4
5
0
Особенности Task-ов (1)
Обозримость. С ней не очень хорошо.
Callback hell. И вот это вот все.
59
Особенности Task-ов (2)
Обработка ошибок.
60
Особенности Task-ов (3)
Отмена task-ов.
Таймеры, таймауты?
61
Читинг
void handle_request(const execution_context & ctx, request req)
{
auto user_info_ft = async(ctx.http_client_ctx(),
[req] { return retrieve_user_info(req.user_id()); });
auto original_image_ft = async(ctx.http_client_ctx(),
[req] { return download_image(req.image_id()); });
when_all(user_info_ft, original_image_ft).then(
[&ctx, req](tuple<future<user_info>, future<image_loaded>> data) {
async(ctx.image_mixer_ctx(), [&ctx, req, d=std::move(data)] {
return mix_image(get<0>(d).get().watermark_image(), get<1>(d).get());
})
.then([req](future<mixed_image> mixed) {
async(ctx.http_srv_ctx(), [req, im=std::move(mixed)] { make_reply(...); });
});
});
}
62
Actors/CSP vs Tasks
Actors/CSP: акцент на обмене информацией.
Tasks: акцент на выполняемых действиях.
63
Куда смотреть, что брать?
С++20 stdlib
https://en.cppreference.com/w/cpp/experimental/concurrency
async++
https://github.com/Amanieu/asyncplusplus
Microsoft's PPL
https://msdn.microsoft.com/en-us/library/dd492427.aspx
64
Еще интересное
Антон Полухин
"Готовимся к С++20. Coroutines TS на реальном примере"
https://habr.com/company/yandex/blog/420861/
65
And now, the end is near...
Пора переходить к итогам
66
Забудьте про голую многопоточность
67
Голой многопоточности есть место только внутри фреймворков и
библиотек.
Есть из чего выбирать
Проверено временем и множеством проектов:
● actors
● communicating sequential processes (CSP)
● tasks (async, promises, futures, ...)
● data flows
● reactive programming
● ...
Для всего этого в C++ есть готовые инструменты (в том числе и
хорошие)
68
The (Happy?) End
Спасибо за внимание!
stiffstream.com
69

More Related Content

What's hot

CodeFest 2011. Крестьянинов М. — Обзор аспектно-ориентированного программиров...
CodeFest 2011. Крестьянинов М. — Обзор аспектно-ориентированного программиров...CodeFest 2011. Крестьянинов М. — Обзор аспектно-ориентированного программиров...
CodeFest 2011. Крестьянинов М. — Обзор аспектно-ориентированного программиров...
CodeFest
 
Юнит-тестирование и Google Mock. Влад Лосев, Google
Юнит-тестирование и Google Mock. Влад Лосев, GoogleЮнит-тестирование и Google Mock. Влад Лосев, Google
Юнит-тестирование и Google Mock. Влад Лосев, Google
yaevents
 
Объектно-Ориентированное Программирование на C++, Лекции 1 и 2
Объектно-Ориентированное Программирование на C++, Лекции 1 и 2Объектно-Ориентированное Программирование на C++, Лекции 1 и 2
Объектно-Ориентированное Программирование на C++, Лекции 1 и 2
Dima Dzuba
 

What's hot (20)

Андрей Карпов, Приватные байки от разработчиков анализатора кода
Андрей Карпов, Приватные байки от разработчиков анализатора кодаАндрей Карпов, Приватные байки от разработчиков анализатора кода
Андрей Карпов, Приватные байки от разработчиков анализатора кода
 
Как за час сделать недельную работу
Как за час сделать недельную работуКак за час сделать недельную работу
Как за час сделать недельную работу
 
C++ refelection and cats
C++ refelection and catsC++ refelection and cats
C++ refelection and cats
 
Современный статический анализ кода: что умеет он, чего не умели линтеры
Современный статический анализ кода: что умеет он, чего не умели линтерыСовременный статический анализ кода: что умеет он, чего не умели линтеры
Современный статический анализ кода: что умеет он, чего не умели линтеры
 
Цена ошибки
Цена ошибкиЦена ошибки
Цена ошибки
 
Юрий Ефимочев, Компилируемые в реальном времени DSL для С++
Юрий Ефимочев, Компилируемые в реальном времени DSL для С++ Юрий Ефимочев, Компилируемые в реальном времени DSL для С++
Юрий Ефимочев, Компилируемые в реальном времени DSL для С++
 
Дмитрий Кашицын, Троллейбус из буханки: алиасинг и векторизация в LLVM
Дмитрий Кашицын, Троллейбус из буханки: алиасинг и векторизация в LLVMДмитрий Кашицын, Троллейбус из буханки: алиасинг и векторизация в LLVM
Дмитрий Кашицын, Троллейбус из буханки: алиасинг и векторизация в LLVM
 
CodeFest 2011. Крестьянинов М. — Обзор аспектно-ориентированного программиров...
CodeFest 2011. Крестьянинов М. — Обзор аспектно-ориентированного программиров...CodeFest 2011. Крестьянинов М. — Обзор аспектно-ориентированного программиров...
CodeFest 2011. Крестьянинов М. — Обзор аспектно-ориентированного программиров...
 
Шишки, набитые за 15 лет использования акторов в C++
Шишки, набитые за 15 лет использования акторов в C++Шишки, набитые за 15 лет использования акторов в C++
Шишки, набитые за 15 лет использования акторов в C++
 
Павел Довгалюк, Обратная отладка
Павел Довгалюк, Обратная отладкаПавел Довгалюк, Обратная отладка
Павел Довгалюк, Обратная отладка
 
Funny JS #2
Funny JS #2Funny JS #2
Funny JS #2
 
Статический анализ кода: Что? Как? Зачем?
Статический анализ кода: Что? Как? Зачем?Статический анализ кода: Что? Как? Зачем?
Статический анализ кода: Что? Как? Зачем?
 
What's in a metrics? Ruby Russia 2018
What's in a metrics? Ruby Russia 2018What's in a metrics? Ruby Russia 2018
What's in a metrics? Ruby Russia 2018
 
Юнит-тестирование и Google Mock. Влад Лосев, Google
Юнит-тестирование и Google Mock. Влад Лосев, GoogleЮнит-тестирование и Google Mock. Влад Лосев, Google
Юнит-тестирование и Google Mock. Влад Лосев, Google
 
Цена ошибки
Цена ошибкиЦена ошибки
Цена ошибки
 
хитрости выведения типов
хитрости выведения типовхитрости выведения типов
хитрости выведения типов
 
Объектно-Ориентированное Программирование на C++, Лекции 1 и 2
Объектно-Ориентированное Программирование на C++, Лекции 1 и 2Объектно-Ориентированное Программирование на C++, Лекции 1 и 2
Объектно-Ориентированное Программирование на C++, Лекции 1 и 2
 
How to get knowledge and improve it all your professional life long
How to get knowledge and improve it all your professional life longHow to get knowledge and improve it all your professional life long
How to get knowledge and improve it all your professional life long
 
Полухин Антон, Как делать не надо: C++ велосипедостроение для профессионалов
Полухин Антон, Как делать не надо: C++ велосипедостроение для профессионаловПолухин Антон, Как делать не надо: C++ велосипедостроение для профессионалов
Полухин Антон, Как делать не надо: C++ велосипедостроение для профессионалов
 
Борис Сазонов, RAII потоки и CancellationToken в C++
Борис Сазонов, RAII потоки и CancellationToken в C++Борис Сазонов, RAII потоки и CancellationToken в C++
Борис Сазонов, RAII потоки и CancellationToken в C++
 

Similar to C++ CoreHard Autumn 2018. Actors vs CSP vs Tasks vs ... - Евгений Охотников

Акторы в C++: взгляд старого практикующего актородела (St. Petersburg C++ Use...
Акторы в C++: взгляд старого практикующего актородела (St. Petersburg C++ Use...Акторы в C++: взгляд старого практикующего актородела (St. Petersburg C++ Use...
Акторы в C++: взгляд старого практикующего актородела (St. Petersburg C++ Use...
Yauheni Akhotnikau
 
20130429 dynamic c_c++_program_analysis-alexey_samsonov
20130429 dynamic c_c++_program_analysis-alexey_samsonov20130429 dynamic c_c++_program_analysis-alexey_samsonov
20130429 dynamic c_c++_program_analysis-alexey_samsonov
Computer Science Club
 
ADD 2011: Статический анализ Си++ кода
ADD 2011: Статический анализ Си++ кодаADD 2011: Статический анализ Си++ кода
ADD 2011: Статический анализ Си++ кода
Andrey Karpov
 
SECON'2014 - Павел Щеваев - Метаданные и автогенерация кода
SECON'2014 - Павел Щеваев - Метаданные и автогенерация кодаSECON'2014 - Павел Щеваев - Метаданные и автогенерация кода
SECON'2014 - Павел Щеваев - Метаданные и автогенерация кода
Конференция разработчиков программного обеспечения SECON'2014
 
Эволюционный дизайн. Joker Students Day 2016
Эволюционный дизайн. Joker Students Day 2016Эволюционный дизайн. Joker Students Day 2016
Эволюционный дизайн. Joker Students Day 2016
Кирилл Толкачёв
 
Ферапонтов_Резюме
Ферапонтов_РезюмеФерапонтов_Резюме
Ферапонтов_Резюме
Oleg Ferapontov
 
Лекция 12 (часть 1): Языки программирования семейства PGAS: Cray Chapel
Лекция 12 (часть 1): Языки программирования семейства PGAS: Cray ChapelЛекция 12 (часть 1): Языки программирования семейства PGAS: Cray Chapel
Лекция 12 (часть 1): Языки программирования семейства PGAS: Cray Chapel
Mikhail Kurnosov
 
23may 1300 valday антон сапожников 'еще один недостаток современных клиент се...
23may 1300 valday антон сапожников 'еще один недостаток современных клиент се...23may 1300 valday антон сапожников 'еще один недостаток современных клиент се...
23may 1300 valday антон сапожников 'еще один недостаток современных клиент се...
Positive Hack Days
 

Similar to C++ CoreHard Autumn 2018. Actors vs CSP vs Tasks vs ... - Евгений Охотников (20)

Акторы в C++: взгляд старого практикующего актородела (St. Petersburg C++ Use...
Акторы в C++: взгляд старого практикующего актородела (St. Petersburg C++ Use...Акторы в C++: взгляд старого практикующего актородела (St. Petersburg C++ Use...
Акторы в C++: взгляд старого практикующего актородела (St. Petersburg C++ Use...
 
Где кончается react native? / Павел Кондратенко (Rambler&Co)
Где кончается react native? / Павел Кондратенко (Rambler&Co)Где кончается react native? / Павел Кондратенко (Rambler&Co)
Где кончается react native? / Павел Кондратенко (Rambler&Co)
 
Для чего мы делали свой акторный фреймворк и что из этого вышло?
Для чего мы делали свой акторный фреймворк и что из этого вышло?Для чего мы делали свой акторный фреймворк и что из этого вышло?
Для чего мы делали свой акторный фреймворк и что из этого вышло?
 
Разница в подходах анализа кода компилятором и выделенным инструментом
Разница в подходах анализа кода компилятором и выделенным инструментомРазница в подходах анализа кода компилятором и выделенным инструментом
Разница в подходах анализа кода компилятором и выделенным инструментом
 
20130429 dynamic c_c++_program_analysis-alexey_samsonov
20130429 dynamic c_c++_program_analysis-alexey_samsonov20130429 dynamic c_c++_program_analysis-alexey_samsonov
20130429 dynamic c_c++_program_analysis-alexey_samsonov
 
Парсим и кодогенерируем для С++ с использованием clang
Парсим и кодогенерируем для С++ с использованием clangПарсим и кодогенерируем для С++ с использованием clang
Парсим и кодогенерируем для С++ с использованием clang
 
Функциональное программирование с использованием библиотеки fp-ts | Odessa Fr...
Функциональное программирование с использованием библиотеки fp-ts | Odessa Fr...Функциональное программирование с использованием библиотеки fp-ts | Odessa Fr...
Функциональное программирование с использованием библиотеки fp-ts | Odessa Fr...
 
Lviv MDDay 2014. Андріан Буданцов “Внутрішній світ iOS додатків”
Lviv MDDay 2014. Андріан Буданцов “Внутрішній світ iOS додатків”Lviv MDDay 2014. Андріан Буданцов “Внутрішній світ iOS додатків”
Lviv MDDay 2014. Андріан Буданцов “Внутрішній світ iOS додатків”
 
Разработка надежных параллельных, распределенных приложений: быстро и дешево
Разработка надежных параллельных, распределенных приложений: быстро и дешевоРазработка надежных параллельных, распределенных приложений: быстро и дешево
Разработка надежных параллельных, распределенных приложений: быстро и дешево
 
Статический анализ Си++ кода
Статический анализ Си++ кодаСтатический анализ Си++ кода
Статический анализ Си++ кода
 
ADD 2011: Статический анализ Си++ кода
ADD 2011: Статический анализ Си++ кодаADD 2011: Статический анализ Си++ кода
ADD 2011: Статический анализ Си++ кода
 
11 встреча — Введение в GPGPU (А. Свириденков)
11 встреча — Введение в GPGPU (А. Свириденков)11 встреча — Введение в GPGPU (А. Свириденков)
11 встреча — Введение в GPGPU (А. Свириденков)
 
SECON'2014 - Павел Щеваев - Метаданные и автогенерация кода
SECON'2014 - Павел Щеваев - Метаданные и автогенерация кодаSECON'2014 - Павел Щеваев - Метаданные и автогенерация кода
SECON'2014 - Павел Щеваев - Метаданные и автогенерация кода
 
Использование C++ для низкоуровневой платформозависимой разработки — Кирилл ...
 Использование C++ для низкоуровневой платформозависимой разработки — Кирилл ... Использование C++ для низкоуровневой платформозависимой разработки — Кирилл ...
Использование C++ для низкоуровневой платформозависимой разработки — Кирилл ...
 
Эволюционный дизайн. Joker Students Day 2016
Эволюционный дизайн. Joker Students Day 2016Эволюционный дизайн. Joker Students Day 2016
Эволюционный дизайн. Joker Students Day 2016
 
[RU] Connecting AutoCAD and Python (by Alex Bausk)
[RU] Connecting AutoCAD and Python (by Alex Bausk)[RU] Connecting AutoCAD and Python (by Alex Bausk)
[RU] Connecting AutoCAD and Python (by Alex Bausk)
 
Ферапонтов_Резюме
Ферапонтов_РезюмеФерапонтов_Резюме
Ферапонтов_Резюме
 
Лекция 12 (часть 1): Языки программирования семейства PGAS: Cray Chapel
Лекция 12 (часть 1): Языки программирования семейства PGAS: Cray ChapelЛекция 12 (часть 1): Языки программирования семейства PGAS: Cray Chapel
Лекция 12 (часть 1): Языки программирования семейства PGAS: Cray Chapel
 
Руслан Гроховецкий "Как Python стал делать погоду в Яндексе"
Руслан Гроховецкий "Как Python стал делать погоду в Яндексе"Руслан Гроховецкий "Как Python стал делать погоду в Яндексе"
Руслан Гроховецкий "Как Python стал делать погоду в Яндексе"
 
23may 1300 valday антон сапожников 'еще один недостаток современных клиент се...
23may 1300 valday антон сапожников 'еще один недостаток современных клиент се...23may 1300 valday антон сапожников 'еще один недостаток современных клиент се...
23may 1300 valday антон сапожников 'еще один недостаток современных клиент се...
 

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++ CoreHard Autumn 2018. Actors vs CSP vs Tasks vs ... - Евгений Охотников

  • 1. C++ CoreHard Autumn 2018 Actors vs CSP vs Tasks... Евгений Охотников
  • 2. Коротко о себе Профессиональный разработчик с 1994-го. ● 1994-2000: АСУ ТП/SCADA и т.п.; ● 2001-2014: телеком, платежные сервисы; ● 2014-...: OpenSource-инструментарий для C++. Автор блога "Размышлизмы eao197" (http://eao197.blogspot.com/) Сооснователь stiffstream.com ⇛ (SObjectizer, RESTinio) Автор ряда докладов про Модель Акторов и С++. 2
  • 4. Не грех повторить еще раз: Многопоточное программирование на C++ посредством голых нитей, mutex-ов и condition variables – это пот, боль и кровь. 4
  • 5. Можно не верить мне... https://habr.com/company/pixonic/blog/426875/ 5 Архитектура мета- сервера мобильного онлайн-шутера Tacticool
  • 6. Можно не верить мне... https://habr.com/company/pixonic/blog/426875/ 6 Архитектура мета- сервера мобильного онлайн-шутера Tacticool Через пару недель, потраченных на поиск и исправление наиболее критических багов, мы решили, что проще переписать все с нуля, чем пытаться исправить все недостатки текущего решения.
  • 7. Почему мы ходим по граблям? Незнание? Лень? NIH-синдром? 7
  • 8. Есть много чего Проверено временем и множеством проектов: ● actors ● communicating sequential processes (CSP) ● tasks (async, promises, futures, ...) ● data flows ● reactive programming ● ... Этому вряд ли учат в ВУЗ-ах. 8
  • 9. Простая задача HTTP-сервер, который: ● принимает запрос (ID картинки, ID пользователя); ● отдает картинку с "водяными знаками", уникальными для этого пользователя. 9
  • 10. Что нужно делать? 10 client our service user database image storage
  • 12. Набор рабочих нитей 12 Http Server Request Processing Http Client (outgoing requests) Image Processing
  • 13. Disclaimer Примеры не привязаны к какому-то конкретному инструменту. Везде есть некий execution_context. 13
  • 15. Модель Акторов. Основные принципы ● актор – это некая сущность, обладающая поведением; ● акторы реагируют на входящие сообщения; ● получив сообщение актор может: ○ отослать некоторое (конечное) количество сообщений другим акторам; ○ создать некоторое (конечное) количество новых акторов; ○ определить для себя новое поведение для обработки последующих сообщений. 15
  • 16. Модель Акторов. Основные принципы ● актор – это некая сущность, обладающая поведением; ● акторы реагируют на входящие сообщения; ● получив сообщение актор может: ○ отослать некоторое (конечное) количество сообщений другим акторам; ○ создать некоторое (конечное) количество новых акторов; ○ определить для себя новое поведение для обработки последующих сообщений. 16 Могут быть реализованы сильно по-разному: ● каждый актор – это отдельный поток ОС; ● каждый актор – это сопрограмма (stackful); ● каждый актор – это объект у которого кто-то вызывает коллбэки. Сейчас будем говорить про акторов виде объектов с коллбэками. Сопрограммы оставим для разговора про CSP.
  • 17. Один из возможных вариантов 17
  • 18. Актор request_handler (1) class request_handler final : public some_basic_type { const execution_context context_; const request request_; optional<user_info> user_info_; optional<image_loaded> image_; void on_start(); void on_user_info(user_info info); void on_image_loaded(image_loaded image); void on_mixed_image(mixed_image image); void send_mix_images_request(); ... // вся специфическая для фреймворка обвязка. }; 18
  • 19. Актор request_handler (2) void request_handler::on_start() { send(context_.user_checker(), check_user{request_.user_id(), self()}); send(context_.image_downloader(), download_image{request_.image_id(), self()}); } 19
  • 20. Актор request_handler (3) void request_handler::on_user_info(user_info info) { user_info_ = std::move(info); if(image_) send_mix_images_request(); } void request_handler::on_image_loaded(image_loaded image) { image_ = std::move(image); if(user_info_) send_mix_images_request(); } 20
  • 21. Актор request_handler (4) void request_handler::send_mix_images_request() { send(context_.image_mixer(), mix_images{user_info->watermark_image(), *image_, self()}); } void request_handler::on_mixed_image(mixed_image image) { send(context_.http_srv(), reply{..., std::move(image), ...}); } 21
  • 22. Особенности Модели Акторов (1) Акторы реактивны. Работают при наличии входящих сообщений. 22
  • 23. Особенности Модели Акторов (2) Акторы подвержены перегрузкам. Следствие асинхронной природы взаимодействия. send не блокирует отправителя. 23
  • 24. Особенности Модели Акторов (3) Много акторов ≠ решение. Зачастую много акторов ⇒ еще одна проблема. 24
  • 25. Куда смотреть, что брать? SObjectizer https://stiffstream.com/en/products/sobjectizer.html C++ Actor Framework (CAF) http://actor-framework.org QP/C++ https://www.state-machine.com/qpcpp/ https://en.wikipedia.org/wiki/Actor_model#Actor_libraries_and_frameworks 25 Поддержи отечественного производителя!
  • 27. CSP на пальцах и без матана Композиция параллельно работающих последовательных процессов. Взаимодействие посредством асинхронных сообщений. Сообщения доставляются посредством каналов. У каналов есть две операции: write (send) и read (receive). 27
  • 28. CSP на пальцах и без матана 28 Композиция параллельно работающих последовательных процессов. Взаимодействие посредством асинхронных сообщений. Сообщения доставляются посредством каналов. У каналов есть две операции: write (send) и read (receive). "Последовательные процессы" внутри одного процесса ОС могут быть реализованы как: ● отдельные нити ОС. В этом случае имеем вытесняющую многозадачность; ● сопрограммы (stackful coroutines, green threads, fibers, ...). В этом случае имеем кооперативную многозадачность.
  • 29. Один из возможных вариантов 29
  • 30. "Процесс" request_handler void request_handler(const execution_context ctx, const request req) { auto user_info_ch = make_chain<user_info>(); auto image_loaded_ch = make_chain<image_loaded>(); ctx.user_checker_ch().write(check_user{req.user_id(), user_info_ch}); ctx.image_downloader_ch().write(download_image{req.image_id(), image_loaded_ch}); auto user = user_info_ch.read(); auto original_image = image_loaded_ch.read(); auto image_mix_ch = make_chain<mixed_image>(); ctx.image_mixer_ch().write( mix_image{user.watermark_image(), std::move(original_image), image_mix_ch}); auto result_image = image_mix_ch.read(); ctx.http_srv_ch().write(reply{..., std::move(result_image), ...}); } 30
  • 31. "Процесс" request_handler void request_handler(const execution_context ctx, const request req) { auto user_info_ch = make_chain<user_info>(); auto image_loaded_ch = make_chain<image_loaded>(); ctx.user_checker_ch().write(check_user{req.user_id(), user_info_ch}); ctx.image_downloader_ch().write(download_image{req.image_id(), image_loaded_ch}); auto user = user_info_ch.read(); auto original_image = image_loaded_ch.read(); auto image_mix_ch = make_chain<mixed_image>(); ctx.image_mixer_ch().write( mix_image{user.watermark_image(), std::move(original_image), image_mix_ch}); auto result_image = image_mix_ch.read(); ctx.http_srv_ch().write(reply{..., std::move(result_image), ...}); } 31
  • 32. "Процесс" request_handler void request_handler(const execution_context ctx, const request req) { auto user_info_ch = make_chain<user_info>(); auto image_loaded_ch = make_chain<image_loaded>(); ctx.user_checker_ch().write(check_user{req.user_id(), user_info_ch}); ctx.image_downloader_ch().write(download_image{req.image_id(), image_loaded_ch}); auto user = user_info_ch.read(); auto original_image = image_loaded_ch.read(); auto image_mix_ch = make_chain<mixed_image>(); ctx.image_mixer_ch().write( mix_image{user.watermark_image(), std::move(original_image), image_mix_ch}); auto result_image = image_mix_ch.read(); ctx.http_srv_ch().write(reply{..., std::move(result_image), ...}); } 32
  • 33. "Процесс" request_handler void request_handler(const execution_context ctx, const request req) { auto user_info_ch = make_chain<user_info>(); auto image_loaded_ch = make_chain<image_loaded>(); ctx.user_checker_ch().write(check_user{req.user_id(), user_info_ch}); ctx.image_downloader_ch().write(download_image{req.image_id(), image_loaded_ch}); auto user = user_info_ch.read(); auto original_image = image_loaded_ch.read(); auto image_mix_ch = make_chain<mixed_image>(); ctx.image_mixer_ch().write( mix_image{user.watermark_image(), std::move(original_image), image_mix_ch}); auto result_image = image_mix_ch.read(); ctx.http_srv_ch().write(reply{..., std::move(result_image), ...}); } 33
  • 34. "Процесс" request_handler void request_handler(const execution_context ctx, const request req) { auto user_info_ch = make_chain<user_info>(); auto image_loaded_ch = make_chain<image_loaded>(); ctx.user_checker_ch().write(check_user{req.user_id(), user_info_ch}); ctx.image_downloader_ch().write(download_image{req.image_id(), image_loaded_ch}); auto user = user_info_ch.read(); auto original_image = image_loaded_ch.read(); auto image_mix_ch = make_chain<mixed_image>(); ctx.image_mixer_ch().write( mix_image{user.watermark_image(), std::move(original_image), image_mix_ch}); auto result_image = image_mix_ch.read(); ctx.http_srv_ch().write(reply{..., std::move(result_image), ...}); } 34
  • 35. "Процесс" request_handler void request_handler(const execution_context ctx, const request req) { auto user_info_ch = make_chain<user_info>(); auto image_loaded_ch = make_chain<image_loaded>(); ctx.user_checker_ch().write(check_user{req.user_id(), user_info_ch}); ctx.image_downloader_ch().write(download_image{req.image_id(), image_loaded_ch}); auto user = user_info_ch.read(); auto original_image = image_loaded_ch.read(); auto image_mix_ch = make_chain<mixed_image>(); ctx.image_mixer_ch().write( mix_image{user.watermark_image(), std::move(original_image), image_mix_ch}); auto result_image = image_mix_ch.read(); ctx.http_srv_ch().write(reply{..., std::move(result_image), ...}); } 35
  • 36. "Процесс" request_handler void request_handler(const execution_context ctx, const request req) { auto user_info_ch = make_chain<user_info>(); auto image_loaded_ch = make_chain<image_loaded>(); ctx.user_checker_ch().write(check_user{req.user_id(), user_info_ch}); ctx.image_downloader_ch().write(download_image{req.image_id(), image_loaded_ch}); auto user = user_info_ch.read(); auto original_image = image_loaded_ch.read(); auto image_mix_ch = make_chain<mixed_image>(); ctx.image_mixer_ch().write( mix_image{user.watermark_image(), std::move(original_image), image_mix_ch}); auto result_image = image_mix_ch.read(); ctx.http_srv_ch().write(reply{..., std::move(result_image), ...}); } 36
  • 37. "Процесс" request_handler void request_handler(const execution_context ctx, const request req) { auto user_info_ch = make_chain<user_info>(); auto image_loaded_ch = make_chain<image_loaded>(); ctx.user_checker_ch().write(check_user{req.user_id(), user_info_ch}); ctx.image_downloader_ch().write(download_image{req.image_id(), image_loaded_ch}); auto user = user_info_ch.read(); auto original_image = image_loaded_ch.read(); auto image_mix_ch = make_chain<mixed_image>(); ctx.image_mixer_ch().write( mix_image{user.watermark_image(), std::move(original_image), image_mix_ch}); auto result_image = image_mix_ch.read(); ctx.http_srv_ch().write(reply{..., std::move(result_image), ...}); } 37
  • 38. Особенности CSP (1) "Процессы" могут вести себя как захотят: быть реактивными, проактивными или чередовать реактивность с проактивностью. "Процессы" могут работать даже в отсутствии сообщений. 38
  • 39. Особенности CSP (2) "Родные" механизмы защиты от перегрузки. Каналы могут быть ограничены по размеру. Где-то только такими и могут быть. Отправитель блокируется при записи в полный канал. 39
  • 40. Особенности CSP (3) "Процессы" в виде нитей ОС ⇒ дорого. Плата за стек. Плата за переключение. Но вытесняющая многозадачность. "Процессы" в виде сопрограмм ⇒ дешево. Но кооперативная многозадачность. Но сюрпризы с 3rd-party libs (thread-local-storage, например). 40
  • 41. Особенности CSP (4) Много "процессов" ≠ решение. Зачастую много "процессов" ⇒ еще одна проблема. 41
  • 42. Куда смотреть, что брать? Boost.Fiber https://www.boost.org SObjectizer https://stiffstream.com/en/products/sobjectizer.html 42
  • 43. Actors vs CSP Actors: один-единственный "канал", только реактивность, могут быть сложными конечными автоматами. CSP-шные процессы: много каналов, и реактивность, и проактивность, не очень хорошо с конечными автоматами, лучше, когда поддерживаются на уровне языка и stdlib 43
  • 45. Про Task-based подход в двух словах Решение строится как набор небольших задач. Каждая задача выполняет одну операцию. Задачи запускаются вызовами async. Результатом async является future. Задачи провязываются в "цепочки" посредством .then(), wait_all(), wait_any(). 45
  • 46. Реализация обработки запроса (1) void handle_request(const execution_context & ctx, request req) { auto user_info_ft = async(ctx.http_client_ctx(), [req] { return retrieve_user_info(req.user_id()); }); auto original_image_ft = async(ctx.http_client_ctx(), [req] { return download_image(req.image_id()); }); when_all(user_info_ft, original_image_ft).then( [&ctx, req](tuple<future<user_info>, future<image_loaded>> data) { async(ctx.image_mixer_ctx(), [&ctx, req, d=std::move(data)] { return mix_image(get<0>(d).get().watermark_image(), get<1>(d).get()); }) .then([req](future<mixed_image> mixed) { async(ctx.http_srv_ctx(), [req, im=std::move(mixed)] { make_reply(...); }); }); }); } 46
  • 47. Реализация обработки запроса (2) void handle_request(const execution_context & ctx, request req) { auto user_info_ft = async(ctx.http_client_ctx(), [req] { return retrieve_user_info(req.user_id()); }); auto original_image_ft = async(ctx.http_client_ctx(), [req] { return download_image(req.image_id()); }); when_all(user_info_ft, original_image_ft).then( [&ctx, req](tuple<future<user_info>, future<image_loaded>> data) { async(ctx.image_mixer_ctx(), [&ctx, req, d=std::move(data)] { return mix_image(get<0>(d).get().watermark_image(), get<1>(d).get()); }) .then([req](future<mixed_image> mixed) { async(ctx.http_srv_ctx(), [req, im=std::move(mixed)] { make_reply(...); }); }); }); } 47
  • 48. Реализация обработки запроса (3) void handle_request(const execution_context & ctx, request req) { auto user_info_ft = async(ctx.http_client_ctx(), [req] { return retrieve_user_info(req.user_id()); }); auto original_image_ft = async(ctx.http_client_ctx(), [req] { return download_image(req.image_id()); }); when_all(user_info_ft, original_image_ft).then( [&ctx, req](tuple<future<user_info>, future<image_loaded>> data) { async(ctx.image_mixer_ctx(), [&ctx, req, d=std::move(data)] { return mix_image(get<0>(d).get().watermark_image(), get<1>(d).get()); }) .then([req](future<mixed_image> mixed) { async(ctx.http_srv_ctx(), [req, im=std::move(mixed)] { make_reply(...); }); }); }); } 48
  • 49. Реализация обработки запроса (4) void handle_request(const execution_context & ctx, request req) { auto user_info_ft = async(ctx.http_client_ctx(), [req] { return retrieve_user_info(req.user_id()); }); auto original_image_ft = async(ctx.http_client_ctx(), [req] { return download_image(req.image_id()); }); when_all(user_info_ft, original_image_ft).then( [&ctx, req](tuple<future<user_info>, future<image_loaded>> data) { async(ctx.image_mixer_ctx(), [&ctx, req, d=std::move(data)] { return mix_image(get<0>(d).get().watermark_image(), get<1>(d).get()); }) .then([req](future<mixed_image> mixed) { async(ctx.http_srv_ctx(), [req, im=std::move(mixed)] { make_reply(...); }); }); }); } 49
  • 50. Реализация обработки запроса (5) void handle_request(const execution_context & ctx, request req) { auto user_info_ft = async(ctx.http_client_ctx(), [req] { return retrieve_user_info(req.user_id()); }); auto original_image_ft = async(ctx.http_client_ctx(), [req] { return download_image(req.image_id()); }); when_all(user_info_ft, original_image_ft).then( [&ctx, req](tuple<future<user_info>, future<image_loaded>> data) { async(ctx.image_mixer_ctx(), [&ctx, req, d=std::move(data)] { return mix_image(get<0>(d).get().watermark_image(), get<1>(d).get()); }) .then([req](future<mixed_image> mixed) { async(ctx.http_srv_ctx(), [req, im=std::move(mixed)] { make_reply(...); }); }); }); } 50
  • 51. Реализация обработки запроса (6) void handle_request(const execution_context & ctx, request req) { auto user_info_ft = async(ctx.http_client_ctx(), [req] { return retrieve_user_info(req.user_id()); }); auto original_image_ft = async(ctx.http_client_ctx(), [req] { return download_image(req.image_id()); }); when_all(user_info_ft, original_image_ft).then( [&ctx, req](tuple<future<user_info>, future<image_loaded>> data) { async(ctx.image_mixer_ctx(), [&ctx, req, d=std::move(data)] { return mix_image(get<0>(d).get().watermark_image(), get<1>(d).get()); }) .then([req](future<mixed_image> mixed) { async(ctx.http_srv_ctx(), [req, im=std::move(mixed)] { make_reply(...); }); }); }); } 51
  • 52. Последовательность операций void handle_request(const execution_context & ctx, request req) { auto user_info_ft = async(ctx.http_client_ctx(), [req] { return retrieve_user_info(req.user_id()); }); auto original_image_ft = async(ctx.http_client_ctx(), [req] { return download_image(req.image_id()); }); when_all(user_info_ft, original_image_ft).then( [&ctx, req](tuple<future<user_info>, future<image_loaded>> data) { async(ctx.image_mixer_ctx(), [&ctx, req, d=std::move(data)] { return mix_image(get<0>(d).get().watermark_image(), get<1>(d).get()); }) .then([req](future<mixed_image> mixed) { async(ctx.http_srv_ctx(), [req, im=std::move(mixed)] { make_reply(...); }); }); }); } 52 1 2 3 4 5
  • 54. Последовательность операций 54 1 2 3 4 5 0 Загрузка user_info Загрузка изображения Есть и изображение, и user_info
  • 55. Последовательность операций 55 1 2 3 4 5 0 Загрузка user_info Загрузка изображения Есть и изображение, и user_info Микширование изображения
  • 56. Последовательность операций 56 1 2 3 4 5 0 Загрузка user_info Загрузка изображения Есть и изображение, и user_info Микширование изображения Изображение смикшировано
  • 57. Последовательность операций 57 1 2 3 4 5 0 Загрузка user_info Загрузка изображения Есть и изображение, и user_info Микширование изображения Изображение смикшировано Формирование ответа на запрос
  • 58. void handle_request(const execution_context & ctx, request req) { auto user_info_ft = async(ctx.http_client_ctx(), [req] { return retrieve_user_info(req.user_id()); }); auto original_image_ft = async(ctx.http_client_ctx(), [req] { return download_image(req.image_id()); }); when_all(user_info_ft, original_image_ft).then( [&ctx, req](tuple<future<user_info>, future<image_loaded>> data) { async(ctx.image_mixer_ctx(), [&ctx, req, d=std::move(data)] { return mix_image(get<0>(d).get().watermark_image(), get<1>(d).get()); }) .then([req](future<mixed_image> mixed) { async(ctx.http_srv_ctx(), [req, im=std::move(mixed)] { make_reply(...); }); }); }); } Последовательность операций 58 1 2 3 4 5 0
  • 59. Особенности Task-ов (1) Обозримость. С ней не очень хорошо. Callback hell. И вот это вот все. 59
  • 61. Особенности Task-ов (3) Отмена task-ов. Таймеры, таймауты? 61
  • 62. Читинг void handle_request(const execution_context & ctx, request req) { auto user_info_ft = async(ctx.http_client_ctx(), [req] { return retrieve_user_info(req.user_id()); }); auto original_image_ft = async(ctx.http_client_ctx(), [req] { return download_image(req.image_id()); }); when_all(user_info_ft, original_image_ft).then( [&ctx, req](tuple<future<user_info>, future<image_loaded>> data) { async(ctx.image_mixer_ctx(), [&ctx, req, d=std::move(data)] { return mix_image(get<0>(d).get().watermark_image(), get<1>(d).get()); }) .then([req](future<mixed_image> mixed) { async(ctx.http_srv_ctx(), [req, im=std::move(mixed)] { make_reply(...); }); }); }); } 62
  • 63. Actors/CSP vs Tasks Actors/CSP: акцент на обмене информацией. Tasks: акцент на выполняемых действиях. 63
  • 64. Куда смотреть, что брать? С++20 stdlib https://en.cppreference.com/w/cpp/experimental/concurrency async++ https://github.com/Amanieu/asyncplusplus Microsoft's PPL https://msdn.microsoft.com/en-us/library/dd492427.aspx 64
  • 65. Еще интересное Антон Полухин "Готовимся к С++20. Coroutines TS на реальном примере" https://habr.com/company/yandex/blog/420861/ 65
  • 66. And now, the end is near... Пора переходить к итогам 66
  • 67. Забудьте про голую многопоточность 67 Голой многопоточности есть место только внутри фреймворков и библиотек.
  • 68. Есть из чего выбирать Проверено временем и множеством проектов: ● actors ● communicating sequential processes (CSP) ● tasks (async, promises, futures, ...) ● data flows ● reactive programming ● ... Для всего этого в C++ есть готовые инструменты (в том числе и хорошие) 68
  • 69. The (Happy?) End Спасибо за внимание! stiffstream.com 69