SlideShare une entreprise Scribd logo
1  sur  48
Télécharger pour lire hors ligne
Асинхронность на
сопрограммах
Демченко Григорий, старший разработчик
C++ party, 27 марта 2014
План рассказа
Реализация сопрограмм
Ожидающие примитивы
Примитивы, использующие планировщик
Обработка внешних событий
Заключение
План рассказа
Реализация сопрограмм
Ожидающие примитивы
Примитивы, использующие планировщик
Обработка внешних событий
Заключение
Сопрограммы
• Подпрограмма:выполняются все действия перед возвратом
управления
• Сопрограмма:частичное выполнение действий перед возвратом
управления
Сопрограмма обобщает понятие подпрограммы, т.е. подпрограмма -
это частный случай сопрограммы.
Примеры сопрограмм:
1. Генераторы (например, на python)
2. Конечный автомат (C# async/await)
3. Модель акторов (как и конечный автомат)
Для эффективной реализации на С++ будем использовать метод
сохранения контекста исполнения (stackful coroutines).
Реализация сопрограмм
• Проблемы
o Сопрограммы никак не описаны в стандарте
o Необходимо применять низкоуровневые операции =>
зависимость от платформы, архитектуры и даже компилятора.
• Решение: использовать boost.context:
o Используется только ассемблер
o Поддержкаплатформ: Windows, Linux, MacOSX
o Поддержка мобильных платформ: Windows Phone, Android, IOS,
o Поддержка архитектур: x86, x86_64, ARM, Spark, Spark64, PPC,
PPC64, MIPS
o Поддержка компиляторов:GCC, Clang, Visual Studio
boost.context
Реализует 2 функции:
• make_fcontext:создает контекст и инициализируетстек
сопрограммы
• jump_fcontext:переходитв новый контекст с сохранением текущего
контекста для последующего возврата
Использование:
1. Выделение памяти под стек.
2. Создание контекста
ctx = make_fcontext(stackPtr, stackSize, callback)
3. Переход: jump_fcontext(callerCtx, ctx, ptr)
4. Возврат: jump_fcontext(ctx, callerCtx, ptr)
Реализация сопрограмм: Coro
void CoroFn() {
CLOG("Yielding...");
Yield();
CLOG("Returning...");
}
CLOG("Starting...");
Coro c(CoroFn);
CLOG("Resuming...");
c.Resume();
CLOG("Completed");
Выдача:
0: Starting...
1: Yielding...
0: Resuming...
1: Returning...
0: Completed
Использование сопрограмм
• Переделываем асинхронный вызов:
PerformAsyncOp(CompletionAction);
• В синхронный с использованием сопрограмм:
PerformOp();
void PerformOp() {
auto& coro = CurrentCoro();
PerformAsyncOp([&coro] { coro.Resume(); });
Yield();
}
Использование сопрограмм
• Scheduler:
boost::asio::io_service
• Thread: std::thread
• Coro: реализация с использованием
boost.context
• Network:
boost::asio::read/write/...
Проблема: состояние гонки
Возможно возобновление
работы сопрограммы до
выхода из нее
Варианты решения:
1. std::mutex
2. boost::asio::strand
3. Defer
Решение: Defer
Defer:откладывание асинхронной
операции до выхода из
сопрограммы
typedef
std::function<void()> Action;
void Defer(Action);
Использование Defer
void PerformOp() {
auto& coro = CurrentCoro();
PerformAsyncOp([&coro] { coro.Resume(); });
Yield();
}
void PerformOp() {
auto& coro = CurrentCoro();
Defer([&coro] {
PerformAsyncOp([&coro] { coro.Resume(); });
});
}
План рассказа
Реализация сопрограмм
Ожидающие примитивы
Примитивы, использующие планировщик
Обработка внешних событий
Заключение
Реализация WaitFor для Future<T>
template<typename T>
T WaitFor(Future<T> future) {
auto& coro = CurrentCoro();
Defer([&coro, &future] {
future.Subscribe([&coro] (const T&) {
coro.Resume();
});
});
return future.Get();
}
Использование WaitFor
• Произведем рефакторинг примера с использованием сопрограмм:
for (;;) {
auto request = WaitFor(GetRequest());
auto payload = WaitFor(QueryBackend(request));
auto response = WaitFor(HandlePayload(payload));
WaitFor(Reply(request, response));
}
for (;;) {
auto request = GetRequestSynca();
auto payload = QueryBackendSynca(request);
auto response = HandlePayloadSynca(payload);
ReplySynca(request, response);
}
Ожидание завершения операции
• Задача: запустить асинхронно операцию и дождаться её завершения.
void GoWait(Action action);
• Проблема обычного подхода: во время ожидания поток остается
заблокированным
• Сопрограммы с легкостью решают эту проблему
Ожидание завершения операции
void GoWait(Action action) {
DeferProceed([&action](Action proceed) {
Go([proceed, &action] { // создаем новую сопрограмму
action();
proceed(); // продолжаем выполнение сопрограммы
});
});
}
void DeferProceed(std::function<void(Action)> proceed) {
auto& coro = CurrentCoro();
Defer([&coro, proceed] {
proceed([&coro] { coro.Resume(); });
});
}
Ожидание завершения операций
• Задача: запустить асинхронно несколько операций и дождаться их
завершения.
void GoWait(std::initializer_list<Action> actions);
• Проблема: во время ожидания поток остается заблокированным
• Сопрограммы с легкостью решают эту проблему
Ожидание завершения операций
void GoWait(std::initializer_list<Action> actions) {
DeferProceed([&actions](Action proceed) {
std::shared_ptr<void> proceeder(
nullptr, [proceed](void*) { proceed(); });
for (const auto& action: actions) {
Go([proceeder, &action] {
action();
});
}
});
}
Ожидание завершения операций
Последовательность вызовов для:
GoWait(action1, action2);
Пример: вычисление числа Фибоначчи
int Fibo(int v) {
if (v < 2)
return v;
int v1, v2;
GoWait({
[v, &v1] { v1 = Fibo(v-1); },
[v, &v2] { v2 = Fibo(v-2); }
});
return v1 + v2;
}
Ожидание завершения любой
операции
• Задача: запустить асинхронно несколько операций и дождаться
завершения самой первой закончившей операции.
size_t GoAnyWait(std::initializer_list<Action> actions);
• Проблема: во время ожидания поток остается заблокированным
• Сопрограммы с легкостью решают эту проблему
Ожидание завершения любой
операции
size_t GoAnyWait(std::initializer_list<Action> actions) {
size_t index = static_cast<size_t>(-1);
DeferProceed([&actions, &index](Action proceed) {
std::shared_ptr<std::atomic<int>> counter = std::make_shared<std::atomic<int>>();
size_t i = 0;
for (const auto& action: actions) {
Go([counter, proceed, &action, i, &index] {
action();
if (++ *counter == 1) {
index = i;
proceed();
}
});
++ i;
}
});
return index;
}
Идея:
std::shared_ptr<std::atomic<int>> counter;
if (++ *counter == 1) {
...
proceed();
}
Ожидание результата
• Задача: запустить асинхронно несколько операций и дождаться самого
первого успешного результата.
template<typename T_result>
boost::optional<T_result> GoAnyResult(
std::initializer_list<
std::function<boost::optional<T_result>()>
> actions);
Использование:
boost::optional<Result> Fn1();
boost::optional<Result> result = GoAnyResult({Fn1, …});
• Проблема: во время ожидания поток остается заблокированным
• Сопрограммы с легкостью решают эту проблему
Ожидание результата
struct Counter {
Counter(ResultAction proceed_) :
proceed(std::move(proceed_)) {}
~Counter() {
TryProceed(Result());
}
void TryProceed(Result&& result) {
if (++ counter == 1)
proceed(std::move(result));
}
private:
std::atomic<int> counter;
ResultAction proceed;
};
План рассказа
Реализация сопрограмм
Ожидающие примитивы
Примитивы, использующие планировщик
Обработка внешних событий
Заключение
Планировщик
• Интерфейс планировщика:
struct IScheduler {
virtual void Schedule(Action action) = 0;
};
• Планировщик отвечает за запуск задач: action
• ThreadPool реализует интерфейс ISchedulerс использованием
boost.asio:
struct ThreadPool : IScheduler {
ThreadPool(size_t thread_count) { … }
void Schedule(Action action) {
service.post(std::move(action));
}
private:
boost::asio::io_service service;
};
Возобновление сопрограммы
• Возобновление работы сопрограммыпроисходит с использованием
планировщика:
struct Journey {
void Proceed() {
scheduler->Schedule([this] {
coro.Resume();
OnComplete();
});
}
void OnComplete(); // вызов action в Defer
// или удаление сопрограммы
private:
IScheduler* scheduler;
Coro coro;
};
Телепортация
• Переключение между планировщиками. Внутри сопрограммы:
ThreadPool tp1(1);
ThreadPool tp2(1);
Go([&tp2] {
JLOG("Inside tp1");
Teleport(tp2);
JLOG("And now inside tp2!!!");
}, tp1);
• Реализация:
void Journey::Teleport(IScheduler& s) {
scheduler = &s;
Defer(ProceedAction());
}
Телепортация
Происходит
переключение
исполнения
сопрограммы с
Scheduler/Thread на
Scheduler2/Thread2
Портал
• Портал - телепортация туда и обратно:
struct Portal {
Portal(IScheduler& destination)
: source(CurrentScheduler()) {
teleport(destination);
}
~Portal() {
teleport(source);
}
private:
IScheduler& source;
};
Использования портала
• Пример использования портала:
struct Network {
void HandleNetworkEvents() {
// долгие и нетривиальные операции
}
};
ThreadPool common(1);
ThreadPool network_pool(1);
GetPortal<Network>().Attach(network_pool);
Go([] {
JLOG("Execution inside common");
GetPortal<Network>()->HandleNetworkEvents();
JLOG("Continue execution inside common");
}, common);
Alone
• Для глобальных объектов часто требуется эксклюзивный доступ.
Обычно используется мьютексы.
• Сопрограммы позволяют ввести новый паттерн: Alone.
struct Alone : IScheduler {
void Schedule(Action action) {
strand.post(std::move(action));
}
private:
boost::asio::io_service::strand strand;
};
• Гарантирует выполнение не более одного action в каждый момент
времени.
Пример использования
ThreadPool tp(3);
Alone a(tp);
Go([&a] {
Go([] {
SleepFor(1000);
}, a);
JLOG("scheduled: 2");
Go([] {
SleepFor(1000);
}, a);
JLOG("scheduled: 3");
Teleport(a);
JLOG("main completed");
}, tp);
Вывод в консоли:
1.001640: tp#3: [1] started
1.007640: tp#3: [1] scheduled: 2
1.009640: tp#2: [2] started
1.013641: tp#3: [1] scheduled: 3
1.016641: tp#2: [2] sleeping: 1000ms
1.018641: tp#3: [1] teleport tp -> a
2.020742: tp#2: [2] ended
2.022742: tp#3: [3] started
2.024742: tp#3: [3] sleeping: 1000ms
3.028842: tp#3: [3] ended
3.031843: tp#3: [1] main completed
3.033843: tp#3: [1] ended
Интегральный пример
struct DiskCache/MemCache {
boost::optional<std::string> Get(const std::string& key);
void Set(const std::string& key, const std::string& val);
};
ThreadPool common_pool(3); // общий пул потоков
ThreadPool disk_pool(2); // пул для дисковых операций
Alone mem_alone(common_pool); // сериализация действий с памятью
GetPortal<DiskCache>().Attach(disk_pool); // привязка портала для диска
GetPortal< MemCache>().Attach(mem_alone); // привязка портала для памяти
boost::optional<std::string> result = GoAnyResult<std::string>({
[&key] { return GetPortal<DiskCache>()->Get(key); },
[&key] { return GetPortal< MemCache>()->Get(key); }
});
Обсуждение использования порталов
struct MemCache {
boost::optional<std::string> Get(const std::string& key);
void Set(const std::string& key, const std::string& val);
};
GetPortal<MemCache>()->Set(key, val);
Дружественность к исключениям
Абстракция от контекста исполнения: возможно использованиес
различными планировщиками.
Порталы – аналог акторов:
– Типы сообщений → методы
– Сообщение → параметры метода
План рассказа
Реализация сопрограмм
Ожидающие примитивы
Примитивы, использующие планировщик
Обработка внешних событий
Заключение
Отмена операций
enum EventStatus {
ES_NORMAL,
ES_CANCELLED,
ES_TIMEDOUT,
};
struct Goer {
bool Cancel() { SetStatus(ES_CANCELLED); }
bool Timedout() { SetStatus(ES_TIMEDOUT ); }
...
private:
std::shared_ptr<EventStatus> state;
};
Использование отмены
• Вызывается в момент переключения контекста внутри Defer:
void Journey::HandleEvents() {
if (state == ES_NORMAL)
return;
throw EventException(state);
}
• Асинхронный запуск сопрограммы:
Goer Go(Action handler[, IScheduler& scheduler]);
• Использование:
Goer g = Go(someAction);
…
g.Cancel();
Таймаут операций
struct Timeout {
Timeout(int ms) : timer(TimeoutSevice(),
boost::posix_time::milliseconds(ms)) {
Goer goer = CurrentGoer();
timer.async_wait([goer](const Error& error) mutable {
if (!error)
goer.Timedout();
});
}
~Timeout() {
timer.cancel_one();
HandleEvents();
}
private:
boost::asio::deadline_timer timer;
};
Таймаут операций: использование
• Допускается использование вложенных таймаутов:
// установка таймаута 200мс на все операции
Timeout outer(200);
GetPortal<MyObject>()->PerformOp();
{
// установка таймаута 100мс
// только на операции внутри области видимости
Timeout inner(100);
GetPortal<MyAnotherObject>()->PerformAnotherOp();
PerformSomeAction();
}
“Отмена отмены”
• Для некоторых действий требуется запретить события:
void Journey::DisableEvents() {
HandleEvents();
events_allowed = false;
}
void Journey::EnableEvents() {
events_allowed = true;
HandleEvents();
}
void Journey::HandleEvents() {
if (!events_allowed || std::uncaught_exception())
return;
...
}
Использование “отмены отмены”
• “Защитник”событий:
struct EventsGuard {
EventsGuard() { DisableEvents(); }
~EventsGuard() { EnableEvents(); }
};
• Использование:
auto result = PerformHeavyStuff();
{
EventsGuard guard;
GetPortal<Cache>()->Insert(result);
}
План рассказа
Реализация сопрограмм
Ожидающие примитивы
Примитивы, использующие планировщик
Обработка внешних событий
Заключение
Теорема
Любую асинхроннуюзадачу можно решить с помощью сопрограмм
1. После вызова код отсутствует:
// код до вызова
Async(..., action);
// код до вызова
Synca(...); action();
2. После вызова код присутствует:
// код до вызова
Async(..., action);
// код после вызова
// код до вызова
Go { Async(..., action); }
// код после вызова
// код до вызова
Go { Synca(...); action(); }
// код после вызова
Выводы
• Простота синхронного подхода
• Эффективность асинхронного подхода
• Бережное использование ресурсов (нет ожиданий)
• Эффективная реализация многопоточных паттернов
• Введение новых паттернов (телепортация, порталы, …)
• Это прикольно!
Код: https://bitbucket.org/gridem/synca
gridem@yandex-team.ru
http://habrahabr.ru/users/gridem
Спасибо за внимание!

Contenu connexe

Tendances

Евгений Рыжков, Андрей Карпов Как потратить 10 лет на разработку анализатора ...
Евгений Рыжков, Андрей Карпов Как потратить 10 лет на разработку анализатора ...Евгений Рыжков, Андрей Карпов Как потратить 10 лет на разработку анализатора ...
Евгений Рыжков, Андрей Карпов Как потратить 10 лет на разработку анализатора ...
Platonov Sergey
 
JavaScript. Event Loop and Timers (in russian)
JavaScript. Event Loop and Timers (in russian)JavaScript. Event Loop and Timers (in russian)
JavaScript. Event Loop and Timers (in russian)
Mikhail Davydov
 
Основы и применение статического анализа кода при разработке лекция 1
Основы и применение статического анализа кода при разработке лекция 1Основы и применение статического анализа кода при разработке лекция 1
Основы и применение статического анализа кода при разработке лекция 1
m2rus
 

Tendances (20)

Полный цикл тестирования React-приложений, Алексей Андросов и Наталья Стусь
Полный цикл тестирования React-приложений, Алексей Андросов и Наталья СтусьПолный цикл тестирования React-приложений, Алексей Андросов и Наталья Стусь
Полный цикл тестирования React-приложений, Алексей Андросов и Наталья Стусь
 
Антон Полухин, Немного о Boost
Антон Полухин, Немного о BoostАнтон Полухин, Немного о Boost
Антон Полухин, Немного о Boost
 
Павел Довгалюк, Обратная отладка
Павел Довгалюк, Обратная отладкаПавел Довгалюк, Обратная отладка
Павел Довгалюк, Обратная отладка
 
C++ STL & Qt. Занятие 05.
C++ STL & Qt. Занятие 05.C++ STL & Qt. Занятие 05.
C++ STL & Qt. Занятие 05.
 
Юрий Ефимочев, Компилируемые в реальном времени DSL для С++
Юрий Ефимочев, Компилируемые в реальном времени DSL для С++ Юрий Ефимочев, Компилируемые в реальном времени DSL для С++
Юрий Ефимочев, Компилируемые в реальном времени DSL для С++
 
C++ STL & Qt. Занятие 10.
C++ STL & Qt. Занятие 10.C++ STL & Qt. Занятие 10.
C++ STL & Qt. Занятие 10.
 
Евгений Рыжков, Андрей Карпов Как потратить 10 лет на разработку анализатора ...
Евгений Рыжков, Андрей Карпов Как потратить 10 лет на разработку анализатора ...Евгений Рыжков, Андрей Карпов Как потратить 10 лет на разработку анализатора ...
Евгений Рыжков, Андрей Карпов Как потратить 10 лет на разработку анализатора ...
 
Component Inspector
Component InspectorComponent Inspector
Component Inspector
 
Александр Фокин, Рефлексия в C++
Александр Фокин, Рефлексия в C++Александр Фокин, Рефлексия в C++
Александр Фокин, Рефлексия в C++
 
C++ STL & Qt. Занятие 04.
C++ STL & Qt. Занятие 04.C++ STL & Qt. Занятие 04.
C++ STL & Qt. Занятие 04.
 
Полухин Антон, Как делать не надо: C++ велосипедостроение для профессионалов
Полухин Антон, Как делать не надо: C++ велосипедостроение для профессионаловПолухин Антон, Как делать не надо: C++ велосипедостроение для профессионалов
Полухин Антон, Как делать не надо: C++ велосипедостроение для профессионалов
 
Борис Сазонов, RAII потоки и CancellationToken в C++
Борис Сазонов, RAII потоки и CancellationToken в C++Борис Сазонов, RAII потоки и CancellationToken в C++
Борис Сазонов, RAII потоки и CancellationToken в C++
 
Что нам стоит DAL построить? Акуляков Артём D2D Just.NET
Что нам стоит DAL построить? Акуляков Артём D2D Just.NETЧто нам стоит DAL построить? Акуляков Артём D2D Just.NET
Что нам стоит DAL построить? Акуляков Артём D2D Just.NET
 
C++ STL & Qt. Занятие 11.
C++ STL & Qt. Занятие 11.C++ STL & Qt. Занятие 11.
C++ STL & Qt. Занятие 11.
 
JavaScript. Event Loop and Timers (in russian)
JavaScript. Event Loop and Timers (in russian)JavaScript. Event Loop and Timers (in russian)
JavaScript. Event Loop and Timers (in russian)
 
Шишки, набитые за 15 лет использования акторов в C++
Шишки, набитые за 15 лет использования акторов в C++Шишки, набитые за 15 лет использования акторов в C++
Шишки, набитые за 15 лет использования акторов в C++
 
2014-10-04 02 Владислав Безверхий. Mocha - покрой frontend по полной
2014-10-04 02 Владислав Безверхий. Mocha - покрой frontend по полной2014-10-04 02 Владислав Безверхий. Mocha - покрой frontend по полной
2014-10-04 02 Владислав Безверхий. Mocha - покрой frontend по полной
 
Основы и применение статического анализа кода при разработке лекция 1
Основы и применение статического анализа кода при разработке лекция 1Основы и применение статического анализа кода при разработке лекция 1
Основы и применение статического анализа кода при разработке лекция 1
 
JavaDay'14
JavaDay'14JavaDay'14
JavaDay'14
 
Контроль качества верстки или как начать делать Makeup
Контроль качества верстки или как начать делать MakeupКонтроль качества верстки или как начать делать Makeup
Контроль качества верстки или как начать делать Makeup
 

Similaire à Григорий Демченко — Асинхронное программирование и сопрограммы

Асинхронные вызовы в .NET
Асинхронные вызовы в .NETАсинхронные вызовы в .NET
Асинхронные вызовы в .NET
Bonart
 
20090720 hpc exercise1
20090720 hpc exercise120090720 hpc exercise1
20090720 hpc exercise1
Michael Karpov
 
вспомогательные алгоритмы
вспомогательные алгоритмывспомогательные алгоритмы
вспомогательные алгоритмы
Елена Ключева
 
2012 03 14_parallel_programming_lecture05
2012 03 14_parallel_programming_lecture052012 03 14_parallel_programming_lecture05
2012 03 14_parallel_programming_lecture05
Computer Science Club
 

Similaire à Григорий Демченко — Асинхронное программирование и сопрограммы (20)

Async
AsyncAsync
Async
 
Luxoft async.net
Luxoft async.netLuxoft async.net
Luxoft async.net
 
Асинхронные вызовы в .NET
Асинхронные вызовы в .NETАсинхронные вызовы в .NET
Асинхронные вызовы в .NET
 
20090720 hpc exercise1
20090720 hpc exercise120090720 hpc exercise1
20090720 hpc exercise1
 
Asynchrony and coroutines
Asynchrony and coroutinesAsynchrony and coroutines
Asynchrony and coroutines
 
C# Desktop. Занятие 16.
C# Desktop. Занятие 16.C# Desktop. Занятие 16.
C# Desktop. Занятие 16.
 
Mike ponomarenko java17-fork-v1.2
Mike ponomarenko java17-fork-v1.2Mike ponomarenko java17-fork-v1.2
Mike ponomarenko java17-fork-v1.2
 
RDSDataSource: Promises
RDSDataSource: PromisesRDSDataSource: Promises
RDSDataSource: Promises
 
вспомогательные алгоритмы
вспомогательные алгоритмывспомогательные алгоритмы
вспомогательные алгоритмы
 
Froglogic Squish
Froglogic Squish Froglogic Squish
Froglogic Squish
 
Антон Довгоброд: Highload и очереди задач на примере PHP + Gearman + Yii2
Антон Довгоброд: Highload и очереди задач на примере PHP + Gearman + Yii2Антон Довгоброд: Highload и очереди задач на примере PHP + Gearman + Yii2
Антон Довгоброд: Highload и очереди задач на примере PHP + Gearman + Yii2
 
ПВТ - осень 2014 - Лекция 3 - Стандарт POSIX Threads
ПВТ - осень 2014 - Лекция 3 - Стандарт POSIX ThreadsПВТ - осень 2014 - Лекция 3 - Стандарт POSIX Threads
ПВТ - осень 2014 - Лекция 3 - Стандарт POSIX Threads
 
Иван Пузыревский — Введение в асинхронное программирование
Иван Пузыревский — Введение в асинхронное программированиеИван Пузыревский — Введение в асинхронное программирование
Иван Пузыревский — Введение в асинхронное программирование
 
Инструментируй это
Инструментируй этоИнструментируй это
Инструментируй это
 
Parallel STL
Parallel STLParallel STL
Parallel STL
 
Wild Async .NET world: AID Kit for boy-scouts
Wild Async .NET world: AID Kit for boy-scoutsWild Async .NET world: AID Kit for boy-scouts
Wild Async .NET world: AID Kit for boy-scouts
 
Кирилл Харьков
Кирилл ХарьковКирилл Харьков
Кирилл Харьков
 
2012 03 14_parallel_programming_lecture05
2012 03 14_parallel_programming_lecture052012 03 14_parallel_programming_lecture05
2012 03 14_parallel_programming_lecture05
 
Киллер-фича языка C# — конструкция async/await
Киллер-фича языка C# — конструкция async/awaitКиллер-фича языка C# — конструкция async/await
Киллер-фича языка C# — конструкция async/await
 
Performance optimisation in javascript
Performance optimisation in javascriptPerformance optimisation in javascript
Performance optimisation in javascript
 

Plus de Yandex

Как принять/организовать работу по поисковой оптимизации сайта, Сергей Царик,...
Как принять/организовать работу по поисковой оптимизации сайта, Сергей Царик,...Как принять/организовать работу по поисковой оптимизации сайта, Сергей Царик,...
Как принять/организовать работу по поисковой оптимизации сайта, Сергей Царик,...
Yandex
 
Структурированные данные, Юлия Тихоход, лекция в Школе вебмастеров Яндекса
Структурированные данные, Юлия Тихоход, лекция в Школе вебмастеров ЯндексаСтруктурированные данные, Юлия Тихоход, лекция в Школе вебмастеров Яндекса
Структурированные данные, Юлия Тихоход, лекция в Школе вебмастеров Яндекса
Yandex
 
Представление сайта в поиске, Сергей Лысенко, лекция в Школе вебмастеров Яндекса
Представление сайта в поиске, Сергей Лысенко, лекция в Школе вебмастеров ЯндексаПредставление сайта в поиске, Сергей Лысенко, лекция в Школе вебмастеров Яндекса
Представление сайта в поиске, Сергей Лысенко, лекция в Школе вебмастеров Яндекса
Yandex
 
Плохие методы продвижения сайта, Екатерины Гладких, лекция в Школе вебмастеро...
Плохие методы продвижения сайта, Екатерины Гладких, лекция в Школе вебмастеро...Плохие методы продвижения сайта, Екатерины Гладких, лекция в Школе вебмастеро...
Плохие методы продвижения сайта, Екатерины Гладких, лекция в Школе вебмастеро...
Yandex
 
Основные принципы ранжирования, Сергей Царик и Антон Роменский, лекция в Школ...
Основные принципы ранжирования, Сергей Царик и Антон Роменский, лекция в Школ...Основные принципы ранжирования, Сергей Царик и Антон Роменский, лекция в Школ...
Основные принципы ранжирования, Сергей Царик и Антон Роменский, лекция в Школ...
Yandex
 
Основные принципы индексирования сайта, Александр Смирнов, лекция в Школе веб...
Основные принципы индексирования сайта, Александр Смирнов, лекция в Школе веб...Основные принципы индексирования сайта, Александр Смирнов, лекция в Школе веб...
Основные принципы индексирования сайта, Александр Смирнов, лекция в Школе веб...
Yandex
 
Мобильное приложение: как и зачем, Александр Лукин, лекция в Школе вебмастеро...
Мобильное приложение: как и зачем, Александр Лукин, лекция в Школе вебмастеро...Мобильное приложение: как и зачем, Александр Лукин, лекция в Школе вебмастеро...
Мобильное приложение: как и зачем, Александр Лукин, лекция в Школе вебмастеро...
Yandex
 
Сайты на мобильных устройствах, Олег Ножичкин, лекция в Школе вебмастеров Янд...
Сайты на мобильных устройствах, Олег Ножичкин, лекция в Школе вебмастеров Янд...Сайты на мобильных устройствах, Олег Ножичкин, лекция в Школе вебмастеров Янд...
Сайты на мобильных устройствах, Олег Ножичкин, лекция в Школе вебмастеров Янд...
Yandex
 
Качественная аналитика сайта, Юрий Батиевский, лекция в Школе вебмастеров Янд...
Качественная аналитика сайта, Юрий Батиевский, лекция в Школе вебмастеров Янд...Качественная аналитика сайта, Юрий Батиевский, лекция в Школе вебмастеров Янд...
Качественная аналитика сайта, Юрий Батиевский, лекция в Школе вебмастеров Янд...
Yandex
 
Что можно и что нужно измерять на сайте, Петр Аброськин, лекция в Школе вебма...
Что можно и что нужно измерять на сайте, Петр Аброськин, лекция в Школе вебма...Что можно и что нужно измерять на сайте, Петр Аброськин, лекция в Школе вебма...
Что можно и что нужно измерять на сайте, Петр Аброськин, лекция в Школе вебма...
Yandex
 
Как правильно поставить ТЗ на создание сайта, Алексей Бородкин, лекция в Школ...
Как правильно поставить ТЗ на создание сайта, Алексей Бородкин, лекция в Школ...Как правильно поставить ТЗ на создание сайта, Алексей Бородкин, лекция в Школ...
Как правильно поставить ТЗ на создание сайта, Алексей Бородкин, лекция в Школ...
Yandex
 
Как защитить свой сайт, Пётр Волков, лекция в Школе вебмастеров
Как защитить свой сайт, Пётр Волков, лекция в Школе вебмастеровКак защитить свой сайт, Пётр Волков, лекция в Школе вебмастеров
Как защитить свой сайт, Пётр Волков, лекция в Школе вебмастеров
Yandex
 
Как правильно составить структуру сайта, Дмитрий Сатин, лекция в Школе вебмас...
Как правильно составить структуру сайта, Дмитрий Сатин, лекция в Школе вебмас...Как правильно составить структуру сайта, Дмитрий Сатин, лекция в Школе вебмас...
Как правильно составить структуру сайта, Дмитрий Сатин, лекция в Школе вебмас...
Yandex
 
Технические особенности создания сайта, Дмитрий Васильева, лекция в Школе веб...
Технические особенности создания сайта, Дмитрий Васильева, лекция в Школе веб...Технические особенности создания сайта, Дмитрий Васильева, лекция в Школе веб...
Технические особенности создания сайта, Дмитрий Васильева, лекция в Школе веб...
Yandex
 
Конструкторы для отдельных элементов сайта, Елена Першина, лекция в Школе веб...
Конструкторы для отдельных элементов сайта, Елена Першина, лекция в Школе веб...Конструкторы для отдельных элементов сайта, Елена Першина, лекция в Школе веб...
Конструкторы для отдельных элементов сайта, Елена Першина, лекция в Школе веб...
Yandex
 
Контент для интернет-магазинов, Катерина Ерошина, лекция в Школе вебмастеров ...
Контент для интернет-магазинов, Катерина Ерошина, лекция в Школе вебмастеров ...Контент для интернет-магазинов, Катерина Ерошина, лекция в Школе вебмастеров ...
Контент для интернет-магазинов, Катерина Ерошина, лекция в Школе вебмастеров ...
Yandex
 
Как написать хороший текст для сайта, Катерина Ерошина, лекция в Школе вебмас...
Как написать хороший текст для сайта, Катерина Ерошина, лекция в Школе вебмас...Как написать хороший текст для сайта, Катерина Ерошина, лекция в Школе вебмас...
Как написать хороший текст для сайта, Катерина Ерошина, лекция в Школе вебмас...
Yandex
 
Usability и дизайн - как не помешать пользователю, Алексей Иванов, лекция в Ш...
Usability и дизайн - как не помешать пользователю, Алексей Иванов, лекция в Ш...Usability и дизайн - как не помешать пользователю, Алексей Иванов, лекция в Ш...
Usability и дизайн - как не помешать пользователю, Алексей Иванов, лекция в Ш...
Yandex
 
Cайт. Зачем он и каким должен быть, Алексей Иванов, лекция в Школе вебмастеро...
Cайт. Зачем он и каким должен быть, Алексей Иванов, лекция в Школе вебмастеро...Cайт. Зачем он и каким должен быть, Алексей Иванов, лекция в Школе вебмастеро...
Cайт. Зачем он и каким должен быть, Алексей Иванов, лекция в Школе вебмастеро...
Yandex
 

Plus de Yandex (20)

Предсказание оттока игроков из World of Tanks
Предсказание оттока игроков из World of TanksПредсказание оттока игроков из World of Tanks
Предсказание оттока игроков из World of Tanks
 
Как принять/организовать работу по поисковой оптимизации сайта, Сергей Царик,...
Как принять/организовать работу по поисковой оптимизации сайта, Сергей Царик,...Как принять/организовать работу по поисковой оптимизации сайта, Сергей Царик,...
Как принять/организовать работу по поисковой оптимизации сайта, Сергей Царик,...
 
Структурированные данные, Юлия Тихоход, лекция в Школе вебмастеров Яндекса
Структурированные данные, Юлия Тихоход, лекция в Школе вебмастеров ЯндексаСтруктурированные данные, Юлия Тихоход, лекция в Школе вебмастеров Яндекса
Структурированные данные, Юлия Тихоход, лекция в Школе вебмастеров Яндекса
 
Представление сайта в поиске, Сергей Лысенко, лекция в Школе вебмастеров Яндекса
Представление сайта в поиске, Сергей Лысенко, лекция в Школе вебмастеров ЯндексаПредставление сайта в поиске, Сергей Лысенко, лекция в Школе вебмастеров Яндекса
Представление сайта в поиске, Сергей Лысенко, лекция в Школе вебмастеров Яндекса
 
Плохие методы продвижения сайта, Екатерины Гладких, лекция в Школе вебмастеро...
Плохие методы продвижения сайта, Екатерины Гладких, лекция в Школе вебмастеро...Плохие методы продвижения сайта, Екатерины Гладких, лекция в Школе вебмастеро...
Плохие методы продвижения сайта, Екатерины Гладких, лекция в Школе вебмастеро...
 
Основные принципы ранжирования, Сергей Царик и Антон Роменский, лекция в Школ...
Основные принципы ранжирования, Сергей Царик и Антон Роменский, лекция в Школ...Основные принципы ранжирования, Сергей Царик и Антон Роменский, лекция в Школ...
Основные принципы ранжирования, Сергей Царик и Антон Роменский, лекция в Школ...
 
Основные принципы индексирования сайта, Александр Смирнов, лекция в Школе веб...
Основные принципы индексирования сайта, Александр Смирнов, лекция в Школе веб...Основные принципы индексирования сайта, Александр Смирнов, лекция в Школе веб...
Основные принципы индексирования сайта, Александр Смирнов, лекция в Школе веб...
 
Мобильное приложение: как и зачем, Александр Лукин, лекция в Школе вебмастеро...
Мобильное приложение: как и зачем, Александр Лукин, лекция в Школе вебмастеро...Мобильное приложение: как и зачем, Александр Лукин, лекция в Школе вебмастеро...
Мобильное приложение: как и зачем, Александр Лукин, лекция в Школе вебмастеро...
 
Сайты на мобильных устройствах, Олег Ножичкин, лекция в Школе вебмастеров Янд...
Сайты на мобильных устройствах, Олег Ножичкин, лекция в Школе вебмастеров Янд...Сайты на мобильных устройствах, Олег Ножичкин, лекция в Школе вебмастеров Янд...
Сайты на мобильных устройствах, Олег Ножичкин, лекция в Школе вебмастеров Янд...
 
Качественная аналитика сайта, Юрий Батиевский, лекция в Школе вебмастеров Янд...
Качественная аналитика сайта, Юрий Батиевский, лекция в Школе вебмастеров Янд...Качественная аналитика сайта, Юрий Батиевский, лекция в Школе вебмастеров Янд...
Качественная аналитика сайта, Юрий Батиевский, лекция в Школе вебмастеров Янд...
 
Что можно и что нужно измерять на сайте, Петр Аброськин, лекция в Школе вебма...
Что можно и что нужно измерять на сайте, Петр Аброськин, лекция в Школе вебма...Что можно и что нужно измерять на сайте, Петр Аброськин, лекция в Школе вебма...
Что можно и что нужно измерять на сайте, Петр Аброськин, лекция в Школе вебма...
 
Как правильно поставить ТЗ на создание сайта, Алексей Бородкин, лекция в Школ...
Как правильно поставить ТЗ на создание сайта, Алексей Бородкин, лекция в Школ...Как правильно поставить ТЗ на создание сайта, Алексей Бородкин, лекция в Школ...
Как правильно поставить ТЗ на создание сайта, Алексей Бородкин, лекция в Школ...
 
Как защитить свой сайт, Пётр Волков, лекция в Школе вебмастеров
Как защитить свой сайт, Пётр Волков, лекция в Школе вебмастеровКак защитить свой сайт, Пётр Волков, лекция в Школе вебмастеров
Как защитить свой сайт, Пётр Волков, лекция в Школе вебмастеров
 
Как правильно составить структуру сайта, Дмитрий Сатин, лекция в Школе вебмас...
Как правильно составить структуру сайта, Дмитрий Сатин, лекция в Школе вебмас...Как правильно составить структуру сайта, Дмитрий Сатин, лекция в Школе вебмас...
Как правильно составить структуру сайта, Дмитрий Сатин, лекция в Школе вебмас...
 
Технические особенности создания сайта, Дмитрий Васильева, лекция в Школе веб...
Технические особенности создания сайта, Дмитрий Васильева, лекция в Школе веб...Технические особенности создания сайта, Дмитрий Васильева, лекция в Школе веб...
Технические особенности создания сайта, Дмитрий Васильева, лекция в Школе веб...
 
Конструкторы для отдельных элементов сайта, Елена Першина, лекция в Школе веб...
Конструкторы для отдельных элементов сайта, Елена Першина, лекция в Школе веб...Конструкторы для отдельных элементов сайта, Елена Першина, лекция в Школе веб...
Конструкторы для отдельных элементов сайта, Елена Першина, лекция в Школе веб...
 
Контент для интернет-магазинов, Катерина Ерошина, лекция в Школе вебмастеров ...
Контент для интернет-магазинов, Катерина Ерошина, лекция в Школе вебмастеров ...Контент для интернет-магазинов, Катерина Ерошина, лекция в Школе вебмастеров ...
Контент для интернет-магазинов, Катерина Ерошина, лекция в Школе вебмастеров ...
 
Как написать хороший текст для сайта, Катерина Ерошина, лекция в Школе вебмас...
Как написать хороший текст для сайта, Катерина Ерошина, лекция в Школе вебмас...Как написать хороший текст для сайта, Катерина Ерошина, лекция в Школе вебмас...
Как написать хороший текст для сайта, Катерина Ерошина, лекция в Школе вебмас...
 
Usability и дизайн - как не помешать пользователю, Алексей Иванов, лекция в Ш...
Usability и дизайн - как не помешать пользователю, Алексей Иванов, лекция в Ш...Usability и дизайн - как не помешать пользователю, Алексей Иванов, лекция в Ш...
Usability и дизайн - как не помешать пользователю, Алексей Иванов, лекция в Ш...
 
Cайт. Зачем он и каким должен быть, Алексей Иванов, лекция в Школе вебмастеро...
Cайт. Зачем он и каким должен быть, Алексей Иванов, лекция в Школе вебмастеро...Cайт. Зачем он и каким должен быть, Алексей Иванов, лекция в Школе вебмастеро...
Cайт. Зачем он и каким должен быть, Алексей Иванов, лекция в Школе вебмастеро...
 

Dernier

CVE. The Fortra's GoAnywhere MFT [RU].pdf
CVE. The Fortra's GoAnywhere MFT [RU].pdfCVE. The Fortra's GoAnywhere MFT [RU].pdf
CVE. The Fortra's GoAnywhere MFT [RU].pdf
Хроники кибер-безопасника
 
Cyberprint. Dark Pink Apt Group [RU].pdf
Cyberprint. Dark Pink Apt Group [RU].pdfCyberprint. Dark Pink Apt Group [RU].pdf
Cyberprint. Dark Pink Apt Group [RU].pdf
Хроники кибер-безопасника
 
Cyber Defense Doctrine Managing the Risk Full Applied Guide to Organizational...
Cyber Defense Doctrine Managing the Risk Full Applied Guide to Organizational...Cyber Defense Doctrine Managing the Risk Full Applied Guide to Organizational...
Cyber Defense Doctrine Managing the Risk Full Applied Guide to Organizational...
Ирония безопасности
 
СИСТЕМА ОЦЕНКИ УЯЗВИМОСТЕЙ CVSS 4.0 / CVSS v4.0 [RU].pdf
СИСТЕМА ОЦЕНКИ УЯЗВИМОСТЕЙ CVSS 4.0 / CVSS v4.0 [RU].pdfСИСТЕМА ОЦЕНКИ УЯЗВИМОСТЕЙ CVSS 4.0 / CVSS v4.0 [RU].pdf
СИСТЕМА ОЦЕНКИ УЯЗВИМОСТЕЙ CVSS 4.0 / CVSS v4.0 [RU].pdf
Хроники кибер-безопасника
 
ИСТОЧНИКИ ИННОВАЦИОННОСТИ КИТАЯ (ПО ВЕРСИИ DGAP) | The Sources of China’s Inn...
ИСТОЧНИКИ ИННОВАЦИОННОСТИ КИТАЯ (ПО ВЕРСИИ DGAP) | The Sources of China’s Inn...ИСТОЧНИКИ ИННОВАЦИОННОСТИ КИТАЯ (ПО ВЕРСИИ DGAP) | The Sources of China’s Inn...
ИСТОЧНИКИ ИННОВАЦИОННОСТИ КИТАЯ (ПО ВЕРСИИ DGAP) | The Sources of China’s Inn...
Ирония безопасности
 
2023 Q4. The Ransomware report. [RU].pdf
2023 Q4. The Ransomware report. [RU].pdf2023 Q4. The Ransomware report. [RU].pdf
2023 Q4. The Ransomware report. [RU].pdf
Хроники кибер-безопасника
 

Dernier (9)

CVE. The Fortra's GoAnywhere MFT [RU].pdf
CVE. The Fortra's GoAnywhere MFT [RU].pdfCVE. The Fortra's GoAnywhere MFT [RU].pdf
CVE. The Fortra's GoAnywhere MFT [RU].pdf
 
Cyberprint. Dark Pink Apt Group [RU].pdf
Cyberprint. Dark Pink Apt Group [RU].pdfCyberprint. Dark Pink Apt Group [RU].pdf
Cyberprint. Dark Pink Apt Group [RU].pdf
 
Cyber Defense Doctrine Managing the Risk Full Applied Guide to Organizational...
Cyber Defense Doctrine Managing the Risk Full Applied Guide to Organizational...Cyber Defense Doctrine Managing the Risk Full Applied Guide to Organizational...
Cyber Defense Doctrine Managing the Risk Full Applied Guide to Organizational...
 
СИСТЕМА ОЦЕНКИ УЯЗВИМОСТЕЙ CVSS 4.0 / CVSS v4.0 [RU].pdf
СИСТЕМА ОЦЕНКИ УЯЗВИМОСТЕЙ CVSS 4.0 / CVSS v4.0 [RU].pdfСИСТЕМА ОЦЕНКИ УЯЗВИМОСТЕЙ CVSS 4.0 / CVSS v4.0 [RU].pdf
СИСТЕМА ОЦЕНКИ УЯЗВИМОСТЕЙ CVSS 4.0 / CVSS v4.0 [RU].pdf
 
Malware. DCRAT (DARK CRYSTAL RAT) [RU].pdf
Malware. DCRAT (DARK CRYSTAL RAT) [RU].pdfMalware. DCRAT (DARK CRYSTAL RAT) [RU].pdf
Malware. DCRAT (DARK CRYSTAL RAT) [RU].pdf
 
ИСТОЧНИКИ ИННОВАЦИОННОСТИ КИТАЯ (ПО ВЕРСИИ DGAP) | The Sources of China’s Inn...
ИСТОЧНИКИ ИННОВАЦИОННОСТИ КИТАЯ (ПО ВЕРСИИ DGAP) | The Sources of China’s Inn...ИСТОЧНИКИ ИННОВАЦИОННОСТИ КИТАЯ (ПО ВЕРСИИ DGAP) | The Sources of China’s Inn...
ИСТОЧНИКИ ИННОВАЦИОННОСТИ КИТАЯ (ПО ВЕРСИИ DGAP) | The Sources of China’s Inn...
 
MS Navigating Incident Response [RU].pdf
MS Navigating Incident Response [RU].pdfMS Navigating Incident Response [RU].pdf
MS Navigating Incident Response [RU].pdf
 
Ransomware_Q3 2023. The report [RU].pdf
Ransomware_Q3 2023.  The report [RU].pdfRansomware_Q3 2023.  The report [RU].pdf
Ransomware_Q3 2023. The report [RU].pdf
 
2023 Q4. The Ransomware report. [RU].pdf
2023 Q4. The Ransomware report. [RU].pdf2023 Q4. The Ransomware report. [RU].pdf
2023 Q4. The Ransomware report. [RU].pdf
 

Григорий Демченко — Асинхронное программирование и сопрограммы

  • 1.
  • 2. Асинхронность на сопрограммах Демченко Григорий, старший разработчик C++ party, 27 марта 2014
  • 3. План рассказа Реализация сопрограмм Ожидающие примитивы Примитивы, использующие планировщик Обработка внешних событий Заключение
  • 4. План рассказа Реализация сопрограмм Ожидающие примитивы Примитивы, использующие планировщик Обработка внешних событий Заключение
  • 5. Сопрограммы • Подпрограмма:выполняются все действия перед возвратом управления • Сопрограмма:частичное выполнение действий перед возвратом управления Сопрограмма обобщает понятие подпрограммы, т.е. подпрограмма - это частный случай сопрограммы. Примеры сопрограмм: 1. Генераторы (например, на python) 2. Конечный автомат (C# async/await) 3. Модель акторов (как и конечный автомат) Для эффективной реализации на С++ будем использовать метод сохранения контекста исполнения (stackful coroutines).
  • 6. Реализация сопрограмм • Проблемы o Сопрограммы никак не описаны в стандарте o Необходимо применять низкоуровневые операции => зависимость от платформы, архитектуры и даже компилятора. • Решение: использовать boost.context: o Используется только ассемблер o Поддержкаплатформ: Windows, Linux, MacOSX o Поддержка мобильных платформ: Windows Phone, Android, IOS, o Поддержка архитектур: x86, x86_64, ARM, Spark, Spark64, PPC, PPC64, MIPS o Поддержка компиляторов:GCC, Clang, Visual Studio
  • 7. boost.context Реализует 2 функции: • make_fcontext:создает контекст и инициализируетстек сопрограммы • jump_fcontext:переходитв новый контекст с сохранением текущего контекста для последующего возврата Использование: 1. Выделение памяти под стек. 2. Создание контекста ctx = make_fcontext(stackPtr, stackSize, callback) 3. Переход: jump_fcontext(callerCtx, ctx, ptr) 4. Возврат: jump_fcontext(ctx, callerCtx, ptr)
  • 8. Реализация сопрограмм: Coro void CoroFn() { CLOG("Yielding..."); Yield(); CLOG("Returning..."); } CLOG("Starting..."); Coro c(CoroFn); CLOG("Resuming..."); c.Resume(); CLOG("Completed"); Выдача: 0: Starting... 1: Yielding... 0: Resuming... 1: Returning... 0: Completed
  • 9. Использование сопрограмм • Переделываем асинхронный вызов: PerformAsyncOp(CompletionAction); • В синхронный с использованием сопрограмм: PerformOp(); void PerformOp() { auto& coro = CurrentCoro(); PerformAsyncOp([&coro] { coro.Resume(); }); Yield(); }
  • 10. Использование сопрограмм • Scheduler: boost::asio::io_service • Thread: std::thread • Coro: реализация с использованием boost.context • Network: boost::asio::read/write/...
  • 11. Проблема: состояние гонки Возможно возобновление работы сопрограммы до выхода из нее Варианты решения: 1. std::mutex 2. boost::asio::strand 3. Defer
  • 12. Решение: Defer Defer:откладывание асинхронной операции до выхода из сопрограммы typedef std::function<void()> Action; void Defer(Action);
  • 13. Использование Defer void PerformOp() { auto& coro = CurrentCoro(); PerformAsyncOp([&coro] { coro.Resume(); }); Yield(); } void PerformOp() { auto& coro = CurrentCoro(); Defer([&coro] { PerformAsyncOp([&coro] { coro.Resume(); }); }); }
  • 14. План рассказа Реализация сопрограмм Ожидающие примитивы Примитивы, использующие планировщик Обработка внешних событий Заключение
  • 15. Реализация WaitFor для Future<T> template<typename T> T WaitFor(Future<T> future) { auto& coro = CurrentCoro(); Defer([&coro, &future] { future.Subscribe([&coro] (const T&) { coro.Resume(); }); }); return future.Get(); }
  • 16. Использование WaitFor • Произведем рефакторинг примера с использованием сопрограмм: for (;;) { auto request = WaitFor(GetRequest()); auto payload = WaitFor(QueryBackend(request)); auto response = WaitFor(HandlePayload(payload)); WaitFor(Reply(request, response)); } for (;;) { auto request = GetRequestSynca(); auto payload = QueryBackendSynca(request); auto response = HandlePayloadSynca(payload); ReplySynca(request, response); }
  • 17. Ожидание завершения операции • Задача: запустить асинхронно операцию и дождаться её завершения. void GoWait(Action action); • Проблема обычного подхода: во время ожидания поток остается заблокированным • Сопрограммы с легкостью решают эту проблему
  • 18. Ожидание завершения операции void GoWait(Action action) { DeferProceed([&action](Action proceed) { Go([proceed, &action] { // создаем новую сопрограмму action(); proceed(); // продолжаем выполнение сопрограммы }); }); } void DeferProceed(std::function<void(Action)> proceed) { auto& coro = CurrentCoro(); Defer([&coro, proceed] { proceed([&coro] { coro.Resume(); }); }); }
  • 19. Ожидание завершения операций • Задача: запустить асинхронно несколько операций и дождаться их завершения. void GoWait(std::initializer_list<Action> actions); • Проблема: во время ожидания поток остается заблокированным • Сопрограммы с легкостью решают эту проблему
  • 20. Ожидание завершения операций void GoWait(std::initializer_list<Action> actions) { DeferProceed([&actions](Action proceed) { std::shared_ptr<void> proceeder( nullptr, [proceed](void*) { proceed(); }); for (const auto& action: actions) { Go([proceeder, &action] { action(); }); } }); }
  • 22. Пример: вычисление числа Фибоначчи int Fibo(int v) { if (v < 2) return v; int v1, v2; GoWait({ [v, &v1] { v1 = Fibo(v-1); }, [v, &v2] { v2 = Fibo(v-2); } }); return v1 + v2; }
  • 23. Ожидание завершения любой операции • Задача: запустить асинхронно несколько операций и дождаться завершения самой первой закончившей операции. size_t GoAnyWait(std::initializer_list<Action> actions); • Проблема: во время ожидания поток остается заблокированным • Сопрограммы с легкостью решают эту проблему
  • 24. Ожидание завершения любой операции size_t GoAnyWait(std::initializer_list<Action> actions) { size_t index = static_cast<size_t>(-1); DeferProceed([&actions, &index](Action proceed) { std::shared_ptr<std::atomic<int>> counter = std::make_shared<std::atomic<int>>(); size_t i = 0; for (const auto& action: actions) { Go([counter, proceed, &action, i, &index] { action(); if (++ *counter == 1) { index = i; proceed(); } }); ++ i; } }); return index; } Идея: std::shared_ptr<std::atomic<int>> counter; if (++ *counter == 1) { ... proceed(); }
  • 25. Ожидание результата • Задача: запустить асинхронно несколько операций и дождаться самого первого успешного результата. template<typename T_result> boost::optional<T_result> GoAnyResult( std::initializer_list< std::function<boost::optional<T_result>()> > actions); Использование: boost::optional<Result> Fn1(); boost::optional<Result> result = GoAnyResult({Fn1, …}); • Проблема: во время ожидания поток остается заблокированным • Сопрограммы с легкостью решают эту проблему
  • 26. Ожидание результата struct Counter { Counter(ResultAction proceed_) : proceed(std::move(proceed_)) {} ~Counter() { TryProceed(Result()); } void TryProceed(Result&& result) { if (++ counter == 1) proceed(std::move(result)); } private: std::atomic<int> counter; ResultAction proceed; };
  • 27. План рассказа Реализация сопрограмм Ожидающие примитивы Примитивы, использующие планировщик Обработка внешних событий Заключение
  • 28. Планировщик • Интерфейс планировщика: struct IScheduler { virtual void Schedule(Action action) = 0; }; • Планировщик отвечает за запуск задач: action • ThreadPool реализует интерфейс ISchedulerс использованием boost.asio: struct ThreadPool : IScheduler { ThreadPool(size_t thread_count) { … } void Schedule(Action action) { service.post(std::move(action)); } private: boost::asio::io_service service; };
  • 29. Возобновление сопрограммы • Возобновление работы сопрограммыпроисходит с использованием планировщика: struct Journey { void Proceed() { scheduler->Schedule([this] { coro.Resume(); OnComplete(); }); } void OnComplete(); // вызов action в Defer // или удаление сопрограммы private: IScheduler* scheduler; Coro coro; };
  • 30. Телепортация • Переключение между планировщиками. Внутри сопрограммы: ThreadPool tp1(1); ThreadPool tp2(1); Go([&tp2] { JLOG("Inside tp1"); Teleport(tp2); JLOG("And now inside tp2!!!"); }, tp1); • Реализация: void Journey::Teleport(IScheduler& s) { scheduler = &s; Defer(ProceedAction()); }
  • 32. Портал • Портал - телепортация туда и обратно: struct Portal { Portal(IScheduler& destination) : source(CurrentScheduler()) { teleport(destination); } ~Portal() { teleport(source); } private: IScheduler& source; };
  • 33. Использования портала • Пример использования портала: struct Network { void HandleNetworkEvents() { // долгие и нетривиальные операции } }; ThreadPool common(1); ThreadPool network_pool(1); GetPortal<Network>().Attach(network_pool); Go([] { JLOG("Execution inside common"); GetPortal<Network>()->HandleNetworkEvents(); JLOG("Continue execution inside common"); }, common);
  • 34. Alone • Для глобальных объектов часто требуется эксклюзивный доступ. Обычно используется мьютексы. • Сопрограммы позволяют ввести новый паттерн: Alone. struct Alone : IScheduler { void Schedule(Action action) { strand.post(std::move(action)); } private: boost::asio::io_service::strand strand; }; • Гарантирует выполнение не более одного action в каждый момент времени.
  • 35. Пример использования ThreadPool tp(3); Alone a(tp); Go([&a] { Go([] { SleepFor(1000); }, a); JLOG("scheduled: 2"); Go([] { SleepFor(1000); }, a); JLOG("scheduled: 3"); Teleport(a); JLOG("main completed"); }, tp); Вывод в консоли: 1.001640: tp#3: [1] started 1.007640: tp#3: [1] scheduled: 2 1.009640: tp#2: [2] started 1.013641: tp#3: [1] scheduled: 3 1.016641: tp#2: [2] sleeping: 1000ms 1.018641: tp#3: [1] teleport tp -> a 2.020742: tp#2: [2] ended 2.022742: tp#3: [3] started 2.024742: tp#3: [3] sleeping: 1000ms 3.028842: tp#3: [3] ended 3.031843: tp#3: [1] main completed 3.033843: tp#3: [1] ended
  • 36. Интегральный пример struct DiskCache/MemCache { boost::optional<std::string> Get(const std::string& key); void Set(const std::string& key, const std::string& val); }; ThreadPool common_pool(3); // общий пул потоков ThreadPool disk_pool(2); // пул для дисковых операций Alone mem_alone(common_pool); // сериализация действий с памятью GetPortal<DiskCache>().Attach(disk_pool); // привязка портала для диска GetPortal< MemCache>().Attach(mem_alone); // привязка портала для памяти boost::optional<std::string> result = GoAnyResult<std::string>({ [&key] { return GetPortal<DiskCache>()->Get(key); }, [&key] { return GetPortal< MemCache>()->Get(key); } });
  • 37. Обсуждение использования порталов struct MemCache { boost::optional<std::string> Get(const std::string& key); void Set(const std::string& key, const std::string& val); }; GetPortal<MemCache>()->Set(key, val); Дружественность к исключениям Абстракция от контекста исполнения: возможно использованиес различными планировщиками. Порталы – аналог акторов: – Типы сообщений → методы – Сообщение → параметры метода
  • 38. План рассказа Реализация сопрограмм Ожидающие примитивы Примитивы, использующие планировщик Обработка внешних событий Заключение
  • 39. Отмена операций enum EventStatus { ES_NORMAL, ES_CANCELLED, ES_TIMEDOUT, }; struct Goer { bool Cancel() { SetStatus(ES_CANCELLED); } bool Timedout() { SetStatus(ES_TIMEDOUT ); } ... private: std::shared_ptr<EventStatus> state; };
  • 40. Использование отмены • Вызывается в момент переключения контекста внутри Defer: void Journey::HandleEvents() { if (state == ES_NORMAL) return; throw EventException(state); } • Асинхронный запуск сопрограммы: Goer Go(Action handler[, IScheduler& scheduler]); • Использование: Goer g = Go(someAction); … g.Cancel();
  • 41. Таймаут операций struct Timeout { Timeout(int ms) : timer(TimeoutSevice(), boost::posix_time::milliseconds(ms)) { Goer goer = CurrentGoer(); timer.async_wait([goer](const Error& error) mutable { if (!error) goer.Timedout(); }); } ~Timeout() { timer.cancel_one(); HandleEvents(); } private: boost::asio::deadline_timer timer; };
  • 42. Таймаут операций: использование • Допускается использование вложенных таймаутов: // установка таймаута 200мс на все операции Timeout outer(200); GetPortal<MyObject>()->PerformOp(); { // установка таймаута 100мс // только на операции внутри области видимости Timeout inner(100); GetPortal<MyAnotherObject>()->PerformAnotherOp(); PerformSomeAction(); }
  • 43. “Отмена отмены” • Для некоторых действий требуется запретить события: void Journey::DisableEvents() { HandleEvents(); events_allowed = false; } void Journey::EnableEvents() { events_allowed = true; HandleEvents(); } void Journey::HandleEvents() { if (!events_allowed || std::uncaught_exception()) return; ... }
  • 44. Использование “отмены отмены” • “Защитник”событий: struct EventsGuard { EventsGuard() { DisableEvents(); } ~EventsGuard() { EnableEvents(); } }; • Использование: auto result = PerformHeavyStuff(); { EventsGuard guard; GetPortal<Cache>()->Insert(result); }
  • 45. План рассказа Реализация сопрограмм Ожидающие примитивы Примитивы, использующие планировщик Обработка внешних событий Заключение
  • 46. Теорема Любую асинхроннуюзадачу можно решить с помощью сопрограмм 1. После вызова код отсутствует: // код до вызова Async(..., action); // код до вызова Synca(...); action(); 2. После вызова код присутствует: // код до вызова Async(..., action); // код после вызова // код до вызова Go { Async(..., action); } // код после вызова // код до вызова Go { Synca(...); action(); } // код после вызова
  • 47. Выводы • Простота синхронного подхода • Эффективность асинхронного подхода • Бережное использование ресурсов (нет ожиданий) • Эффективная реализация многопоточных паттернов • Введение новых паттернов (телепортация, порталы, …) • Это прикольно! Код: https://bitbucket.org/gridem/synca gridem@yandex-team.ru http://habrahabr.ru/users/gridem