Павел Сушин «Асинхронное программирование на С++: callbacks, futures, fibers»
Асинхронное 
программирование на С+ 
+: callbacks, futures, fibers. 
Павел Сушин, старший разработчик 
Группа разработки технологий распределенных вычислений
Чем я занимаюсь 
• Отказоустойчивое, консистентное, 
транзакционное хранилище. 
• Несколько слоев хранения, с 
разными гарантиями на throughput и 
latency. 
• Вычисления в модели Map-Reduce 
поверх этих данных. 
• Серверная часть – 100% С++ 
• ~10 кластеров, ~2500 машин, ~25 Pb 
данных, сотни пользователей. 
3 
YT – распределенная система хранения и обработки 
данных.
Принцип №1 
4 
O_NONBLOCK
Принцип №2 
5 
Thread 2 
Thread 3 
Thread 1 
Process state
Принцип №2* 
6 
SingleThreadInvoker 
Thread 
callback 
callback 
lock-free 
queue 
struct IInvoker { 
virtual void Invoke(callback) = 0; 
}; 
• Тред + очередь 
• Пул тредов + очередь 
• Тред + несколько очередей с 
приоритетами 
• …
Принцип №3 
Счетчики ссылок: TRefCounted + TIntrusivePtr + TWeakPtr 
7 
ChunkManager Chunk 
ReadChunk
Callbacks 
8 
struct IAction { 
virtual void Run() = 0; 
}; 
template <class R> 
struct IFunc { 
virtual R Run() = 0; 
}; 
template <class R, class T> 
struct IParamFunc { 
virtual R Run(T t) = 0; 
}; 
template <class T> 
struct IParamAction { 
virtual void Run(T t) = 0; 
};
Callbacks 
9 
class TRequest; class TResponse; 
void SendMessage( 
TRequest req, 
IParamAction<TResponse> response); 
class TResponseHandler 
: public IParamAction<TResponse> 
{ 
public: 
TResponseHandler(TRequest req); 
void Run(TResponse rsp); 
}; 
... 
TRequest req; 
TResponseHandler handler(req); 
SendMessage(req, handler); 
...
10 
Jpg, Png
Callbacks 
11 
int Sum(int a, int b) { 
return a + b; 
} 
void CallAndPrint(TCallback<void(int)> f) 
{ 
std::cout << f.Run() << std::endl; 
} 
auto f = BIND(&Sum, 1); 
auto g = BIND(f, 2); 
CallAndPrint(g);
Почему не std::function? 
• Видно в RefCountedTracker 
• BIND - сохраняет информацию о точке связывания 
• Compile-time проверки 
12 
class T : public TRefCounted { 
... 
void Foo() { 
BIND(&T::Foo, this); // Compile-time error 
BIND(&T::Foo, MakeStrong(this)); 
BIND(&T::Foo, MakeWeak(this)); 
} 
};
Callbacks 
13 
class TRequest; class TResponse; 
void SendRequest( 
TRequest req, 
TCallback<void(TResponse)> callback); 
void ResponseHandler(TRequest req, TResponse rsp); 
... 
TRequest req; 
SendRequest(req, BIND(ResponseHandler, req)); 
В каком потоке будет вызван ResponseHandler?
TCallback::Via 
14 
Привязываем запуск TCallback к конкретному инвокеру 
TCallback<void()> 
TCallback<void()>::Via(IInvoker* invoker) { 
return BIND([=]() { 
invoker->Invoke(*this); 
}); 
} 
IInvoker* invoker; 
TRequest req; 
SendRequest( 
req, 
BIND(ResponseHandler, req).Via(invoker));
Callbacks: проблемы 
• Плохие возможности по композиции: 
• как дождаться окончания двух асинхронных 
действий? 
• как дважды подписаться на одно событие? 
• как составлять цепочки асинхронных 
вычислений? 
• Акцент на коллбеках, а не на результате действия. 
15
16 
Jpg, Png
Future/Promise 
17 
template <class T> 
class TFuture 
{ 
public: 
bool IsSet() const; 
T Get() const; 
void Subscribe( 
TCallback<void(T)> cb); 
}; 
template <class T> 
class TPromise 
{ 
public: 
TFuture<T> ToFuture() const; 
void Set(T t); 
}; 
Promise Future 
Set T Get
Future/Promise 
18 
Future смещает акцент с вызова коллбека на 
результат асинхронного вычисления. 
void DoHeavyStuff(TCallback<void()> cb); 
TFuture<void> AsyncDoHeavyStuff() { 
auto promise = NewPromise<void>(); 
DoHeavyStuff([promise] () { 
promise.Set(); 
}); 
return promise.ToFuture(); 
}
Future/Promise 
19 
class TRequest; class TResponse; 
TFuture<TResponse> SendRequest(TRequest req); 
void ResponseHandler(TRequest req, TResponse rsp); 
... 
IInvoker* invoker; 
TRequest req; 
SendRequest(req).Subscribe( 
BIND(ResponseHandler, req) 
.Via(invoker));
TCallback::AsyncVia 
20 
Как делегировать вычисление в другой поток? 
TCallback<TFuture<T>()> 
TCallback<T>()>::AsyncVia(IInvoker* invoker) 
{ 
return BIND([=] () { 
auto promise = NewPromise<T>(); 
invoker->Invoke(BIND([=] () { 
promise.Set(this->Run()); 
})); 
return promise.ToFuture(); 
}); 
}
TCallback + TFuture 
21 
int GetNthPiDigit(int n); 
BIND(&GetNthPiDigit) // TCallback<int(int)> 
.AsyncVia(workerPool) // TCallback<TFuture<int>(int)> 
.Run(100) // TFuture<int> 
.Subscribe( 
BIND(&OnDone) 
.Via(controlThread));
TFuture::Apply 
22 
Как связывать асинхронные действия в цепочки? 
template <class T> 
class TFuture<T> { 
bool IsSet() const; 
const T& Get() const; 
void Subscribe(TCallback<void(T)> cb); 
TFuture<R> Apply(TCallback<R(T)> f); 
TFuture<R> Apply(TCallback<TFuture<R>(T)> f); 
};
TFuture::Apply 
23 
template <class T> template <class R> 
TFuture<R> TFuture<T>::Apply(TCallback<R(T)> f) 
{ 
auto promise = NewPromise<R>(); 
this->Subscribe(BIND([promise] (T t) { 
auto result = f(t); 
promise.Set(result); 
})); 
return promise.ToFuture(); 
}
TFuture::Apply 
24 
TFuture<int> value = AsyncGetValue(); 
value.Subscribe(BIND([] (int v) { 
std::cerr << “Value is: “ << v << std::endl; 
})); 
TFuture<int> anotherValue = value 
.Apply(BIND([] (int v) { return 2 * v; })); 
TFuture<int> yetAnotherValue = value 
.Apply(BIND([] (int v) { return 2 * v; })) 
.Apply(BIND([] (int u) { return u + 1; })) 
.Apply(BIND([] (int w) { return w * w; }));
TCallback + TFuture 
25 
TFuture<string> SendByNetwork(string block); 
string EncodeRequest(TRequest req); 
TResponse DecodeResponse(string blob); 
IInvoker* workerPool; 
TFuture<TResponse> SendMessage(TRequest req) { 
auto futureBlob = BIND(&EncodeRequest, req) 
.AsyncVia(workerPool) 
.Run(); 
return futureBlob 
.Apply(&SendByNetwork) 
.Apply(BIND(&DecodeResponse).AsyncVia(workerPool)); 
}
Обработка ошибок 
26 
template <class T> 
class TErrorOr<T> { 
TErrorOr<T>(T value); 
TErrorOr<T>(std::exception ex); 
const T& GetOrThrow() const; 
} 
TCallback<TErrorOr<T>()> TCallback<T>()>::Guarded() { 
try { 
return TErrorOr(this->Run()); 
} catch (…) { 
return TErrorOr(std::current_exception()); 
} 
}
Callbacks + Futures: проблемы 
27 
• Как прерывать цепочки при возникновении ошибок? 
• Как запускать многостадийные асинхронные 
вычисления со сложной логикой перехода между 
стадиями? 
Хочется «склеивать» асинхронные вычисления в 
(псевдо)синхронном стиле: 
T WaitFor(TFuture<T> future); 
Значит нужно самостоятельно планировать 
(псевдо)потоки, в которых выполняются 
(псевдо)синхронные вычисления.
Fibers 
28 
TFuture<string> SendByNetwork(string block); 
string EncodeRequest(TRequest req); 
TResponse DecodeResponse(string blob); 
IInvoker* workerPool; 
TFuture<TResponse> SendMessage(TRequest req) { 
auto reqBlob = WaitFor(BIND(&EncodeRequest, req) 
.AsyncVia(workerPool) 
.Run()); 
auto rspBlob = WaitFor(SendByNetwork(reqBlob)); 
return BIND(&DecodeResponse, rspBlob) 
.AsyncVia(workerPool) 
.Run(); 
}
Fibers 
• Контекст = состояние регистров 
• Нужно уметь сохранять и переключать контекст 
(например использовать libcoro) 
• Fiber = контекст + стек 
• У треда есть очередь (готовых) файберов и собственный 
контекст, где он разгребает эту очередь (scheduling 
context) 
• Текущий файбер разгребает очередь коллбеков 
29
Fibers 
30 
• При вызове WaitFor: 
• переходим в scheduling context; 
• подписываем на future добавление 
файбера в очередь готовых; 
• достаем очередной готовый файбер из 
очереди (или создаем новый) и ставим 
на исполнение
Overview 
31 
struct IInvoker { 
virtual void Invoke(TCallback<void()>) = 0; 
}; 
template <class R, class...TArgs> 
class TCallback { 
public: 
... 
TCallback<R(...TArgs)> Via(IInvoker* invoker); 
TCallback<TFuture<R>(...TArgs)> 
AsyncVia(IInvoker* invoker); 
}
Overview 
32 
template <class T> 
class TFuture<T> { 
bool IsSet() const; 
const T& Get() const; 
void Subscribe(TCallback<void(T)> cb); 
TFuture<R> Apply(TCallback<R(T)> f); 
TFuture<R> Apply(TCallback<TFuture<R>(T)> f); 
}; 
T WaitFor(TFuture<T> future);
Спасибо! 
Павел Сушин, старший разработчик 
Группа разработки технологий распределенных 
вычислений 
+7 916 9529490 
psushin@yandex-team. 
ru 
http://twitter.com/ya_events 
http://facebook.com/yandex.ev 
ents

More Related Content

PDF
Игорь Кудрин, «Используем неизменяемые данные и создаем качественный код»
PDF
Максим Хижинский Lock-free maps
PDF
Григорий Демченко, “Асинхронность и сопрограммы: обработка данных“
PPTX
Михаил Матросов, “С++ без new и delete”
PDF
Юрий Ефимочев, Компилируемые в реальном времени DSL для С++
PDF
Продолжаем говорить о микрооптимизациях .NET-приложений
PDF
ПВТ - весна 2015 - Лекция 5. Многопоточное программирование в С++. Синхрониза...
PDF
Функционально декларативный дизайн на C++
Игорь Кудрин, «Используем неизменяемые данные и создаем качественный код»
Максим Хижинский Lock-free maps
Григорий Демченко, “Асинхронность и сопрограммы: обработка данных“
Михаил Матросов, “С++ без new и delete”
Юрий Ефимочев, Компилируемые в реальном времени DSL для С++
Продолжаем говорить о микрооптимизациях .NET-приложений
ПВТ - весна 2015 - Лекция 5. Многопоточное программирование в С++. Синхрониза...
Функционально декларативный дизайн на C++

What's hot (20)

PDF
Лекция 8: Многопоточное программирование: Intel Threading Building Blocks
PDF
ПВТ - весна 2015 - Лекция 4. Шаблоны многопоточного программирования
PDF
Догнать и перегнать boost::lexical_cast
PDF
Лекция 8. Intel Threading Building Blocks
PDF
Дмитрий Кашицын, Троллейбус из буханки: алиасинг и векторизация в LLVM
PDF
ПВТ - осень 2014 - Лекция 5 - Многопоточное программирование в языке С++. Р...
PDF
Распространённые ошибки оценки производительности .NET-приложений
PDF
ПВТ - весна 2015 - Лекция 3. Реентерабельность. Сигналы. Локальные данные пот...
PDF
ПВТ - весна 2015 - Лекция 8. Многопоточное программирование без использования...
PDF
Конкурентные ассоциативные контейнеры
PDF
Tech Talks @NSU: Как приручить дракона: введение в LLVM
PDF
Алексей Куканов — Параллелизм в C++: управляйте приложением, а не потоками!
PDF
Python&Printer / Андрей Пучко / penta.by
PPTX
разработка серверов и серверных приложений лекция №3
PPTX
Обобщенное программирование в C++ или как сделать свою жизнь проще через стра...
PDF
Поговорим о микрооптимизациях .NET-приложений
PDF
ПВТ - осень 2014 - Лекция 6 - Атомарные операции. Внеочередное выполнение инс...
PDF
ПВТ - осень 2014 - Лекция 7. Многопоточное программирование без блокировок. М...
PDF
Семинар 3. Многопоточное программирование на OpenMP (часть 3)
PPTX
разработка серверов и серверных приложений лекция №2
Лекция 8: Многопоточное программирование: Intel Threading Building Blocks
ПВТ - весна 2015 - Лекция 4. Шаблоны многопоточного программирования
Догнать и перегнать boost::lexical_cast
Лекция 8. Intel Threading Building Blocks
Дмитрий Кашицын, Троллейбус из буханки: алиасинг и векторизация в LLVM
ПВТ - осень 2014 - Лекция 5 - Многопоточное программирование в языке С++. Р...
Распространённые ошибки оценки производительности .NET-приложений
ПВТ - весна 2015 - Лекция 3. Реентерабельность. Сигналы. Локальные данные пот...
ПВТ - весна 2015 - Лекция 8. Многопоточное программирование без использования...
Конкурентные ассоциативные контейнеры
Tech Talks @NSU: Как приручить дракона: введение в LLVM
Алексей Куканов — Параллелизм в C++: управляйте приложением, а не потоками!
Python&Printer / Андрей Пучко / penta.by
разработка серверов и серверных приложений лекция №3
Обобщенное программирование в C++ или как сделать свою жизнь проще через стра...
Поговорим о микрооптимизациях .NET-приложений
ПВТ - осень 2014 - Лекция 6 - Атомарные операции. Внеочередное выполнение инс...
ПВТ - осень 2014 - Лекция 7. Многопоточное программирование без блокировок. М...
Семинар 3. Многопоточное программирование на OpenMP (часть 3)
разработка серверов и серверных приложений лекция №2
Ad

Similar to Павел Сушин «Асинхронное программирование на С++: callbacks, futures, fibers» (20)

PPTX
Опыт разработки статического анализатора кода
PDF
Cpp0x Introduction
PDF
Иван Пузыревский — Введение в асинхронное программирование
PDF
Сверхоптимизация кода на Python
PDF
Сверхоптимизация кода на Python
PPTX
разработка серверов и серверных приложений лекция №2
PDF
ПВТ - весна 2015 - Лекция 2. POSIX Threads. Основные понятия многопоточного п...
PPTX
разработка серверов и серверных приложений лекция №3
PDF
Сложности микробенчмаркинга
PPTX
Статический анализ кода
PPTX
статический анализ кода
PDF
Евгений Крутько — Опыт внедрения технологий параллельных вычислений для повыш...
PDF
Распространённые ошибки оценки производительности .NET-приложений
PPTX
Статический и динамический полиморфизм в C++, Дмитрий Леванов
PDF
ПВТ - осень 2014 - Лекция 3 - Стандарт POSIX Threads
PPTX
Павел Беликов, Как избежать ошибок, используя современный C++
PDF
Филипп Торчинский «Анализ производительности и отладка приложений с помощью D...
PDF
Aleksei Milovidov "Let's optimize one aggregate function in ClickHouse"
PDF
Flink CEP и немного магии...
PDF
1 встреча — Параллельное программирование (А. Свириденков)
Опыт разработки статического анализатора кода
Cpp0x Introduction
Иван Пузыревский — Введение в асинхронное программирование
Сверхоптимизация кода на Python
Сверхоптимизация кода на Python
разработка серверов и серверных приложений лекция №2
ПВТ - весна 2015 - Лекция 2. POSIX Threads. Основные понятия многопоточного п...
разработка серверов и серверных приложений лекция №3
Сложности микробенчмаркинга
Статический анализ кода
статический анализ кода
Евгений Крутько — Опыт внедрения технологий параллельных вычислений для повыш...
Распространённые ошибки оценки производительности .NET-приложений
Статический и динамический полиморфизм в C++, Дмитрий Леванов
ПВТ - осень 2014 - Лекция 3 - Стандарт POSIX Threads
Павел Беликов, Как избежать ошибок, используя современный C++
Филипп Торчинский «Анализ производительности и отладка приложений с помощью D...
Aleksei Milovidov "Let's optimize one aggregate function in ClickHouse"
Flink CEP и немного магии...
1 встреча — Параллельное программирование (А. Свириденков)
Ad

More from Platonov Sergey (20)

PPTX
Евгений Зуев, С++ в России: Стандарт языка и его реализация
PPTX
Алексей Кутумов, C++ без исключений, часть 3
PPTX
Евгений Рыжков, Андрей Карпов Как потратить 10 лет на разработку анализатора ...
PPT
Евгений Крутько, Многопоточные вычисления, современный подход.
PDF
Тененёв Анатолий, Boost.Asio в алгоритмической торговле
PPTX
Павел Беликов, Опыт мигрирования крупного проекта с Windows-only на Linux
PDF
Дмитрий Кашицын, Вывод типов в динамических и не очень языках II
PDF
Дмитрий Кашицын, Вывод типов в динамических и не очень языках I
PDF
QML\Qt Quick на практике
PDF
Визуализация автомобильных маршрутов
PDF
Функциональный микроскоп: линзы в C++
PDF
C++ exceptions
PPTX
Как мы уменьшили количество ошибок в Unreal Engine с помощью статического ана...
PDF
HPX: C++11 runtime система для параллельных и распределённых вычислений
PPTX
Ranges calendar-novosibirsk-2015-08
PDF
Использование maven для сборки больших модульных c++ проектов на примере Odin...
PDF
Дракон в мешке: от LLVM к C++ и проблемам неопределенного поведения
PDF
One definition rule - что это такое, и как с этим жить
PDF
DI в C++ тонкости и нюансы
PPTX
Аскетичная разработка браузера
Евгений Зуев, С++ в России: Стандарт языка и его реализация
Алексей Кутумов, C++ без исключений, часть 3
Евгений Рыжков, Андрей Карпов Как потратить 10 лет на разработку анализатора ...
Евгений Крутько, Многопоточные вычисления, современный подход.
Тененёв Анатолий, Boost.Asio в алгоритмической торговле
Павел Беликов, Опыт мигрирования крупного проекта с Windows-only на Linux
Дмитрий Кашицын, Вывод типов в динамических и не очень языках II
Дмитрий Кашицын, Вывод типов в динамических и не очень языках I
QML\Qt Quick на практике
Визуализация автомобильных маршрутов
Функциональный микроскоп: линзы в C++
C++ exceptions
Как мы уменьшили количество ошибок в Unreal Engine с помощью статического ана...
HPX: C++11 runtime система для параллельных и распределённых вычислений
Ranges calendar-novosibirsk-2015-08
Использование maven для сборки больших модульных c++ проектов на примере Odin...
Дракон в мешке: от LLVM к C++ и проблемам неопределенного поведения
One definition rule - что это такое, и как с этим жить
DI в C++ тонкости и нюансы
Аскетичная разработка браузера

Павел Сушин «Асинхронное программирование на С++: callbacks, futures, fibers»

  • 2. Асинхронное программирование на С+ +: callbacks, futures, fibers. Павел Сушин, старший разработчик Группа разработки технологий распределенных вычислений
  • 3. Чем я занимаюсь • Отказоустойчивое, консистентное, транзакционное хранилище. • Несколько слоев хранения, с разными гарантиями на throughput и latency. • Вычисления в модели Map-Reduce поверх этих данных. • Серверная часть – 100% С++ • ~10 кластеров, ~2500 машин, ~25 Pb данных, сотни пользователей. 3 YT – распределенная система хранения и обработки данных.
  • 5. Принцип №2 5 Thread 2 Thread 3 Thread 1 Process state
  • 6. Принцип №2* 6 SingleThreadInvoker Thread callback callback lock-free queue struct IInvoker { virtual void Invoke(callback) = 0; }; • Тред + очередь • Пул тредов + очередь • Тред + несколько очередей с приоритетами • …
  • 7. Принцип №3 Счетчики ссылок: TRefCounted + TIntrusivePtr + TWeakPtr 7 ChunkManager Chunk ReadChunk
  • 8. Callbacks 8 struct IAction { virtual void Run() = 0; }; template <class R> struct IFunc { virtual R Run() = 0; }; template <class R, class T> struct IParamFunc { virtual R Run(T t) = 0; }; template <class T> struct IParamAction { virtual void Run(T t) = 0; };
  • 9. Callbacks 9 class TRequest; class TResponse; void SendMessage( TRequest req, IParamAction<TResponse> response); class TResponseHandler : public IParamAction<TResponse> { public: TResponseHandler(TRequest req); void Run(TResponse rsp); }; ... TRequest req; TResponseHandler handler(req); SendMessage(req, handler); ...
  • 11. Callbacks 11 int Sum(int a, int b) { return a + b; } void CallAndPrint(TCallback<void(int)> f) { std::cout << f.Run() << std::endl; } auto f = BIND(&Sum, 1); auto g = BIND(f, 2); CallAndPrint(g);
  • 12. Почему не std::function? • Видно в RefCountedTracker • BIND - сохраняет информацию о точке связывания • Compile-time проверки 12 class T : public TRefCounted { ... void Foo() { BIND(&T::Foo, this); // Compile-time error BIND(&T::Foo, MakeStrong(this)); BIND(&T::Foo, MakeWeak(this)); } };
  • 13. Callbacks 13 class TRequest; class TResponse; void SendRequest( TRequest req, TCallback<void(TResponse)> callback); void ResponseHandler(TRequest req, TResponse rsp); ... TRequest req; SendRequest(req, BIND(ResponseHandler, req)); В каком потоке будет вызван ResponseHandler?
  • 14. TCallback::Via 14 Привязываем запуск TCallback к конкретному инвокеру TCallback<void()> TCallback<void()>::Via(IInvoker* invoker) { return BIND([=]() { invoker->Invoke(*this); }); } IInvoker* invoker; TRequest req; SendRequest( req, BIND(ResponseHandler, req).Via(invoker));
  • 15. Callbacks: проблемы • Плохие возможности по композиции: • как дождаться окончания двух асинхронных действий? • как дважды подписаться на одно событие? • как составлять цепочки асинхронных вычислений? • Акцент на коллбеках, а не на результате действия. 15
  • 17. Future/Promise 17 template <class T> class TFuture { public: bool IsSet() const; T Get() const; void Subscribe( TCallback<void(T)> cb); }; template <class T> class TPromise { public: TFuture<T> ToFuture() const; void Set(T t); }; Promise Future Set T Get
  • 18. Future/Promise 18 Future смещает акцент с вызова коллбека на результат асинхронного вычисления. void DoHeavyStuff(TCallback<void()> cb); TFuture<void> AsyncDoHeavyStuff() { auto promise = NewPromise<void>(); DoHeavyStuff([promise] () { promise.Set(); }); return promise.ToFuture(); }
  • 19. Future/Promise 19 class TRequest; class TResponse; TFuture<TResponse> SendRequest(TRequest req); void ResponseHandler(TRequest req, TResponse rsp); ... IInvoker* invoker; TRequest req; SendRequest(req).Subscribe( BIND(ResponseHandler, req) .Via(invoker));
  • 20. TCallback::AsyncVia 20 Как делегировать вычисление в другой поток? TCallback<TFuture<T>()> TCallback<T>()>::AsyncVia(IInvoker* invoker) { return BIND([=] () { auto promise = NewPromise<T>(); invoker->Invoke(BIND([=] () { promise.Set(this->Run()); })); return promise.ToFuture(); }); }
  • 21. TCallback + TFuture 21 int GetNthPiDigit(int n); BIND(&GetNthPiDigit) // TCallback<int(int)> .AsyncVia(workerPool) // TCallback<TFuture<int>(int)> .Run(100) // TFuture<int> .Subscribe( BIND(&OnDone) .Via(controlThread));
  • 22. TFuture::Apply 22 Как связывать асинхронные действия в цепочки? template <class T> class TFuture<T> { bool IsSet() const; const T& Get() const; void Subscribe(TCallback<void(T)> cb); TFuture<R> Apply(TCallback<R(T)> f); TFuture<R> Apply(TCallback<TFuture<R>(T)> f); };
  • 23. TFuture::Apply 23 template <class T> template <class R> TFuture<R> TFuture<T>::Apply(TCallback<R(T)> f) { auto promise = NewPromise<R>(); this->Subscribe(BIND([promise] (T t) { auto result = f(t); promise.Set(result); })); return promise.ToFuture(); }
  • 24. TFuture::Apply 24 TFuture<int> value = AsyncGetValue(); value.Subscribe(BIND([] (int v) { std::cerr << “Value is: “ << v << std::endl; })); TFuture<int> anotherValue = value .Apply(BIND([] (int v) { return 2 * v; })); TFuture<int> yetAnotherValue = value .Apply(BIND([] (int v) { return 2 * v; })) .Apply(BIND([] (int u) { return u + 1; })) .Apply(BIND([] (int w) { return w * w; }));
  • 25. TCallback + TFuture 25 TFuture<string> SendByNetwork(string block); string EncodeRequest(TRequest req); TResponse DecodeResponse(string blob); IInvoker* workerPool; TFuture<TResponse> SendMessage(TRequest req) { auto futureBlob = BIND(&EncodeRequest, req) .AsyncVia(workerPool) .Run(); return futureBlob .Apply(&SendByNetwork) .Apply(BIND(&DecodeResponse).AsyncVia(workerPool)); }
  • 26. Обработка ошибок 26 template <class T> class TErrorOr<T> { TErrorOr<T>(T value); TErrorOr<T>(std::exception ex); const T& GetOrThrow() const; } TCallback<TErrorOr<T>()> TCallback<T>()>::Guarded() { try { return TErrorOr(this->Run()); } catch (…) { return TErrorOr(std::current_exception()); } }
  • 27. Callbacks + Futures: проблемы 27 • Как прерывать цепочки при возникновении ошибок? • Как запускать многостадийные асинхронные вычисления со сложной логикой перехода между стадиями? Хочется «склеивать» асинхронные вычисления в (псевдо)синхронном стиле: T WaitFor(TFuture<T> future); Значит нужно самостоятельно планировать (псевдо)потоки, в которых выполняются (псевдо)синхронные вычисления.
  • 28. Fibers 28 TFuture<string> SendByNetwork(string block); string EncodeRequest(TRequest req); TResponse DecodeResponse(string blob); IInvoker* workerPool; TFuture<TResponse> SendMessage(TRequest req) { auto reqBlob = WaitFor(BIND(&EncodeRequest, req) .AsyncVia(workerPool) .Run()); auto rspBlob = WaitFor(SendByNetwork(reqBlob)); return BIND(&DecodeResponse, rspBlob) .AsyncVia(workerPool) .Run(); }
  • 29. Fibers • Контекст = состояние регистров • Нужно уметь сохранять и переключать контекст (например использовать libcoro) • Fiber = контекст + стек • У треда есть очередь (готовых) файберов и собственный контекст, где он разгребает эту очередь (scheduling context) • Текущий файбер разгребает очередь коллбеков 29
  • 30. Fibers 30 • При вызове WaitFor: • переходим в scheduling context; • подписываем на future добавление файбера в очередь готовых; • достаем очередной готовый файбер из очереди (или создаем новый) и ставим на исполнение
  • 31. Overview 31 struct IInvoker { virtual void Invoke(TCallback<void()>) = 0; }; template <class R, class...TArgs> class TCallback { public: ... TCallback<R(...TArgs)> Via(IInvoker* invoker); TCallback<TFuture<R>(...TArgs)> AsyncVia(IInvoker* invoker); }
  • 32. Overview 32 template <class T> class TFuture<T> { bool IsSet() const; const T& Get() const; void Subscribe(TCallback<void(T)> cb); TFuture<R> Apply(TCallback<R(T)> f); TFuture<R> Apply(TCallback<TFuture<R>(T)> f); }; T WaitFor(TFuture<T> future);
  • 33. Спасибо! Павел Сушин, старший разработчик Группа разработки технологий распределенных вычислений +7 916 9529490 psushin@yandex-team. ru http://twitter.com/ya_events http://facebook.com/yandex.ev ents