SlideShare a Scribd company logo
Asynchrony and coroutines
Асинхронность и сопрограммы
Григорий Демченко, разработчик YT, 2017
План
▌Введение
▌Сопрограммы
▌Планировщики
▌Синхронизация
▌Примеры
▌Заключение
Введение
4
Синхронный многопоточный сервер
5
void multitheadedServer() {
Acceptor acceptor{80}; // слушаем 80 порт
while (true) {
auto socket = acceptor.accept(); // 1-й блокирующий вызов
thread([socket] {
auto request = socket.read(); // 2-й блокирующий вызов
auto response = handleRequest(request);
socket.write(response); // 3-й блокирующий вызов
}).detach();
}
}
Асинхронный сервер
6
void asynchronousServer() {
Acceptor acceptor{80};
acceptor.onAccept([] (auto socket) { // 1-й асинхронный вызов
socket.onRead([socket](auto request) { // 2-й асинхронный вызов
auto response = handleRequest(request);
socket.onWrite(response, []() { // 3-й асинхронный вызов
// завершение
});
});
// продолжаем принимать соединения...
});
}
Реальный асинхронный сервер
7
void realAsynchronousServer() {
Acceptor acceptor{80};
Handler accepting = [&acceptor, &accepting] {
struct Connection {
explicit Connection(Socket sock) : socket(std::move(sock)) {}
void onConnect() {
if (error)
return onError(error);
socket.onRead([this](const Request& request, const Error& error) {
if (error)
return onError(error);
response = handlerRequest(request);
socket.onWrite(response, [this](const Error& error) {
if (error)
return onError(error);
onDone();
});
});
}
private:
void onError(const Error& error) {
delete this;
}
void onDone() {
delete this;
}
Response response;
Socket socket;
};
acceptor.onAccept([&accepting](Socket socket, const Error& error) {
if (!error) {
(new Connection{socket})->onConnect();
accepting();
}
});
};
}
▌ Сравните:
void asynchronousServer() {
Acceptor acceptor{80};
acceptor.onAccept([] (socket) {
socket.onRead([socket](request) {
response = handleRequest(request);
socket.onWrite(response, []() {
// завершение
});
});
// продолжаем принимать соединения
});
}
Асинхронный сервер: обсуждение
8
▌ Плюсы:
› Производительность
› Автоматическая параллелизация исполнения
▌ Минусы:
› Сложность:
1.Нелинейный рост сложности и проблем
2.Явная передача контекста исполнения
3.Обработка ошибок
4.Время жизни объектов
5.Отладка
Что бы хотелось?
9
▌Использовать эффективность асинхронного подхода
▌Использовать простоту синхронного подхода
│ Решение: использовать
│ сопрограммы
10
Сопрограммы
Сопрограммы
▌ Подпрограмма: результат доступен сразу после завершения.
▌ Сопрограмма: результат будет доступен позже. Точка вызова
и точка получения результата разнесены
Примеры сопрограмм:
▌ Генераторы на языке Python.
▌ Async/await C++ proposal.
Метод сохранения контекста исполнения:
▌ Stackful сопрограммы.
12
Реализация сопрограмм
13
Проблема
▌ Сопрограммы пока еще не являются частью языка
▌ Необходимо применять низкоуровневые примитивы.
Решение: boost.context:
▌ Эффективное решение: использование ассемблера
▌ Десктопные платформы: Windows, Linux, MacOSX
▌ Мобильные платформы: Windows Phone, Android, IOS
▌ Процессоры: x86, ARM, Spark, Spark64, PPC, PPC64, MIPS
▌ Компиляторы: GCC, Clang, Visual Studio
boost.context
14
Работа с контекстом:
▌ make_fcontext: создает контекст
▌ jump_fcontext: переключает контекст
Контекст исполнения:
▌ execution_context<Args…>: создает контекст исполнения
Конструктор принимает сигнатуру:
▌ execution_context(execution_context ctx, Args… args)
Сопрограммы в действии
15
void coroFun() {
log << "2";
yield();
log << "4";
}
log << "1";
Coro c{coroFun};
log << "3";
c.resume();
log << "5";
Вывод:
▌ 12345
Использование сопрограммы
16
Преобразовать асинхронный вызов:
async(completionCallback);
В синхронный:
synca(); // async -> synca
Используя следующий подход:
void synca() {
auto& coro = currentCoro();
async([&coro] {
coro.resume();
});
yield();
}
Sequence Diagram
17
Проблема: состояние гонки
18
Возможные решения
19
▌std::mutex
▌boost::asio::strand
▌defer
Использование defer
20
▌ defer откладывает асинхронный вызов:
using Handler = std::function<void()>;
void defer(Handler handler);
Решение: defer
21
Использование: defer
22
void synca() {
auto& coro = currentCoro();
async([&coro] {
coro.resume();
});
yield();
}
void synca() {
auto& coro = currentCoro();
defer([&coro] {
async([&coro] {
coro.resume();
});
});
}
Абстрагирование от сопрограмм
23
void synca() {
auto& coro = currentCoro();
defer([&coro] {
async([&coro] {
coro.resume();
});
});
}
void synca() {
deferProceed([](Handler proceed) {
async(proceed);
});
}
Synca сервер
24
void syncaServer() {
Acceptor acceptor{80};
while (true) {
auto socket = acceptor.accept();
go([socket] { // стартуем новую сопрограмму
auto request = socket.read();
auto response = handleRequest(request);
socket.write(response);
});
}
}
Планировщики
Планировщик
▌ Интерфейс планировщика:
struct IScheduler {
virtual void schedule(Handler) = 0;
};
Планировщик запускает обработчики.
Пул потоков
27
struct ThreadPool : IScheduler {
explicit ThreadPool(size_t threads);
void schedule(Handler handler) {
service.post(std::move(handler));
}
private:
boost::asio::io_service service;
};
Сопрограммы и планировщик
28
struct Journey {
void defer(Handler handler) {
deferHandler = std::move(handler);
yield();
}
void proceed() {
scheduler->schedule([this] {
coro.resume();
deferHandler();
});
}
private:
IScheduler* scheduler;
Coro coro;
Handler deferHandler;
};
Телепортация
29
▌ Давайте перепрыгнем на другой планировщик:
go([&] {
log << "Inside 1st thread pool";
teleport(tp2);
log << “Inside 2nd thread pool";
}, tp1);
▌ Реализация:
void Journey::teleport(IScheduler& s) {
scheduler = &s;
defer([this] {
proceed();
});
}
Телепортация: Sequence Diagram
30
Порталы
31
▌ Портал – это RAII телепортация:
struct Portal {
Portal(IScheduler& destination)
: source{currentScheduler()} {
teleport(destination);
}
~Portal() {
teleport(source);
}
private:
IScheduler& source;
};
Использование порталов
32
struct Network {
void handleNetworkEvents() {
// действия внутри сетевого пула потоков
}
};
ThreadPool commonPool{4};
ThreadPool networkPool{2};
portal<Network>().attach(networkPool);
go([] {
log << "Inside common pool";
portal<Network>()->handleNetworkEvents();
log << "Inside common pool";
}, commonPool);
│ Портал – абстракция
│ среды исполнения
33
Синхронизация
Alone
35
struct Alone : IScheduler {
void schedule(Handler handler) {
strand.post(std::move(handler));
}
private:
boost::asio::io_service::strand strand;
};
strand гарантирует, что ни один обработчик не будет запущен
параллельно с другим
│ Alone – это
│ неблокирующая
│ синхронизация
│ без дедлоков
36
Примеры
Интегральный пример: инициализация
38
struct DiskCache/MemCache {
optional<string> get(const string& key);
void set(const string& key, const string& val);
};
struct Network {
string performRequest(const string& key);
};
ThreadPool commonPool{3}; // общий пул операций
ThreadPool diskPool{2}; // дисковый пул операций
ThreadPool netPool{1}; // сетевой пул операций
Alone memAlone{commonPool}; // MemCache синхронизация
portal<DiskCache>().attach(diskPool);
portal<MemCache>().attach(memAlone);
portal<Network>().attach(netPool);
Интегральный пример: получение значения
39
string obtainValue(const string& key) {
auto res = portal<MemCache>()->get(key);
if (res)
return *res;
res = portal<DiskCache>()->get(key);
if (res)
return *res;
auto val = portal<Network>()->performRequest(key);
go([key, val] {
portal<MemCache>()->set(key, val);
portal<DiskCache>()->set(key, val);
});
return val;
}
Свойства портала
40
▌Работает с исключениями
▌Абстрагирует контекст исполнения
Заключение
▌ 2. Есть код после вызова:
// код до
async(..., cb);
// код после
// код до
go { async(..., cb); };
// код после
// код до
go { synca(...); cb(); };
// код после
Теорема
42
Любая асинхронная задача может быть реализована через сопрограммы
▌ 1. Нет кода после вызова:
// код до
async(params..., cb);
// отсутствует код
// код до
synca(params...);
cb();
Выводы
43
▌ Синхронный подход: простота
▌ Асинхронный подход : эффективность
▌ Неблокирующая синхронизация без дедлоков
▌ Прозрачно для использования
▌ Работает с исключениями
▌ Работа с вложенными таймаутами
▌ Отмена операций
▌ Принципиально новые подходы и паттерны
▌ Это прикольно!
Асинхронность и сопрограммы
habrahabr.ru/users/gridem
gridem.blogspot.com github.com/gridem
bitbucket.org/gridem
Григорий Демченко, Разработчик YT
44

More Related Content

PDF
Hunting for a C++ package manager
PPTX
Применение фреймворка GStreamer в системе видеонаблюдения
PDF
Модульность и управляемая многопоточность встраиваемых С++ приложений - трудн...
PDF
Семь тысяч Rps, один go
ODP
Как за час сделать недельную работу
PPTX
Григорий Демченко, Асинхронность и неблокирующая синхронизация
PDF
Дмитрий Кашицын, Троллейбус из буханки: алиасинг и векторизация в LLVM
PPTX
Александр Тарасенко, Использование python для автоматизации отладки С/C++ код...
Hunting for a C++ package manager
Применение фреймворка GStreamer в системе видеонаблюдения
Модульность и управляемая многопоточность встраиваемых С++ приложений - трудн...
Семь тысяч Rps, один go
Как за час сделать недельную работу
Григорий Демченко, Асинхронность и неблокирующая синхронизация
Дмитрий Кашицын, Троллейбус из буханки: алиасинг и векторизация в LLVM
Александр Тарасенко, Использование python для автоматизации отладки С/C++ код...

What's hot (20)

PDF
Быстрое прототипирование бэкенда игры с геолокацией на OpenResty, Redis и Doc...
PDF
Юрий Ефимочев, Компилируемые в реальном времени DSL для С++
PDF
Использование юнит-тестов для повышения качества разработки
PDF
Антон Полухин, Немного о Boost
PDF
Павел Довгалюк, Обратная отладка
PDF
Практика Lock-free. RealTime-сервер
ODP
Boost.Algorithm: что, зачем и почему
PDF
Полухин Антон, Как делать не надо: C++ велосипедостроение для профессионалов
PDF
Для чего мы делали свой акторный фреймворк и что из этого вышло?
PPTX
Автоматизация тестирования клиентской производительности / Николай Лавлинский...
PPTX
Некоторые паттерны реализации полиморфного поведения в C++ – Дмитрий Леванов,...
PPTX
MySQL 5.7 - NoSQL - JSON, Protocol X, Document Store / Петр Зайцев (Percona)
PPTX
Использование шаблонов и RTTI для конфигурации симулятора флеш-накопителя - Г...
PDF
Цена ошибки
PDF
Владимир Алаев "Разработка на Node.js: инструменты, библиотеки, сервисы"
PDF
Григорий Демченко — Асинхронное программирование и сопрограммы
PPTX
Когда в C# не хватает C++ . Часть 2.
PPTX
Когда в C# не хватает C++ . Часть 3.
PPTX
Когда в C# не хватает C++
PPTX
Асинхронность и сопрограммы
Быстрое прототипирование бэкенда игры с геолокацией на OpenResty, Redis и Doc...
Юрий Ефимочев, Компилируемые в реальном времени DSL для С++
Использование юнит-тестов для повышения качества разработки
Антон Полухин, Немного о Boost
Павел Довгалюк, Обратная отладка
Практика Lock-free. RealTime-сервер
Boost.Algorithm: что, зачем и почему
Полухин Антон, Как делать не надо: C++ велосипедостроение для профессионалов
Для чего мы делали свой акторный фреймворк и что из этого вышло?
Автоматизация тестирования клиентской производительности / Николай Лавлинский...
Некоторые паттерны реализации полиморфного поведения в C++ – Дмитрий Леванов,...
MySQL 5.7 - NoSQL - JSON, Protocol X, Document Store / Петр Зайцев (Percona)
Использование шаблонов и RTTI для конфигурации симулятора флеш-накопителя - Г...
Цена ошибки
Владимир Алаев "Разработка на Node.js: инструменты, библиотеки, сервисы"
Григорий Демченко — Асинхронное программирование и сопрограммы
Когда в C# не хватает C++ . Часть 2.
Когда в C# не хватает C++ . Часть 3.
Когда в C# не хватает C++
Асинхронность и сопрограммы
Ad

Similar to Asynchrony and coroutines (20)

PPTX
Ловля сетями. Инструменты отладки сетевых запросов приложений / Дмитрий Рыбак...
PPTX
OpenStack - Python Project with 12 Million Lines of code (RUS, Moscow Python ...
PDF
JPoint 2016 - Etudes of DIY Java profiler
PDF
Многопоточность в браузере. Модель акторов — Константин Крамлих
PDF
Tarantool Modules, Tarantool Meetup 2016-08-25
PPTX
Node.js введение в технологию, КПИ #ITmeetingKPI
PPTX
Web осень 2013 лекция 5
PDF
JavaDay'14
PDF
Леонид Васильев "Python в инфраструктуре поиска"
PDF
Андрей Светлов-«Делаем своё решение для оптимальной загрузки кластера»
PDF
Лекция 6. Стандарт OpenMP
PPTX
Транзакционный фреймворк для сингловых игр и игр с асинхронным мультиплеером ...
PPTX
javaaaaddawdawdawdasdsadsaddadadm11n.pptx
PPTX
Multithreading in java past and actual
PPTX
Миграция данных из Oracle в Postgres
PPTX
#PostgreSQLRussia 2015.09.15 - Максим Трегубов, CUSTIS - Миграция из Oracle в...
PDF
Превышаем скоростные лимиты с Angular 2
PDF
Превышаем скоростные лимиты с Angular 2 / Алексей Охрименко (IPONWEB)
ODP
Scorex framework
PPT
Пора ли отправлять С на свалку истории? Пишем демонов на PHP с использованием...
Ловля сетями. Инструменты отладки сетевых запросов приложений / Дмитрий Рыбак...
OpenStack - Python Project with 12 Million Lines of code (RUS, Moscow Python ...
JPoint 2016 - Etudes of DIY Java profiler
Многопоточность в браузере. Модель акторов — Константин Крамлих
Tarantool Modules, Tarantool Meetup 2016-08-25
Node.js введение в технологию, КПИ #ITmeetingKPI
Web осень 2013 лекция 5
JavaDay'14
Леонид Васильев "Python в инфраструктуре поиска"
Андрей Светлов-«Делаем своё решение для оптимальной загрузки кластера»
Лекция 6. Стандарт OpenMP
Транзакционный фреймворк для сингловых игр и игр с асинхронным мультиплеером ...
javaaaaddawdawdawdasdsadsaddadadm11n.pptx
Multithreading in java past and actual
Миграция данных из Oracle в Postgres
#PostgreSQLRussia 2015.09.15 - Максим Трегубов, CUSTIS - Миграция из Oracle в...
Превышаем скоростные лимиты с Angular 2
Превышаем скоростные лимиты с Angular 2 / Алексей Охрименко (IPONWEB)
Scorex framework
Пора ли отправлять С на свалку истории? Пишем демонов на PHP с использованием...
Ad

More from corehard_by (20)

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

Asynchrony and coroutines