1
2 
карты 
Асинхронная 
разработка на C++ 
Дмитрий Жестилевский
3 
Содержание 
! Как работает загрузка карты 
! Стейт-машина и линейный код 
! С++11 concurrency 
! Наш вариант concurrenc...
4
5 
Тайл 
! Можно отменять 
! Должен кешироваться 
! Должен обновляться 
! Один тайл может содержать множество версий
6 
Схема загрузки одного тайла 
Старт 
Есть 
в памяти? 
Сходить в диск 
Есть 
на диске? 
Сходить в сеть 
Обновился? 
Конец...
7 
Конечный автомат 
Он же стейт-машина
Row<NotInRam , RequestTile , LoadingFromDisk , none , none >,! 
Row<NotInRam , DiscardTile , none , none , none >,! 
Row<N...
9 
Линейный код 
void loadTile(int x, int y, output_iterator output) {! 
if (auto tile = inMemory(x, y)) {! 
output << til...
10 
C++11 concurrency
Promise<int> promise;! 
11 
Future/Promise 
Promise<int> p;! 
Future<int> f = p.future();! 
Future Promise 
auto future = ...
12 
Использование Future 
output 
int meaningOfLife() {! 
sleep(100500);! 
return 42;! 
}! 
! 
int main() {! 
std::future<...
13 
std::async 
Пример реализации std::async в случае создания отдельного 
потока на каждую операцию 
Future<T> async(Func...
14 
IO binding 
Использование асинхронной сети в синхронном коде 
void NetworkingAPI::httpGet(std::string url, ! 
std::fun...
15 
Чего нет в std:: 
! Масштабируемость 
! Отменяемость асинхронных операций 
! Генераторы — функции, возвращающие множес...
16 
Контексты исполнения 
! Потоки 
! Процессы
17 
Coroutine – user-space thread 
Пишем асинхронный код синхронно
18 
Примитивы 
async::Future! 
async::Promise! 
async::Mutex! 
async::CV! 
Coroutines! 
Coro Scheduler! 
std::future! 
std...
19 
Модель потоков 
Все взаимодействие с IO – в отдельных выделенных потоках 
(сеть, диск) 
Все остальное – в глобальном t...
20 
Отмена операций 
! Отмена через exception (Future.reset, ~Future) 
! Cancellation points: wait, sleep, get 
! Мгновенн...
21 
Генераторы
22 
Поточная десериализация 
Генератор1: байты 
Генератор2: байты объекты 
MultiFuture<char> networkBytes();! 
! 
MultiFut...
23 
Схема загрузки одного тайла 
Старт 
Есть 
в памяти? 
Сходить в диск 
Есть 
на диске? 
Сходить в сеть 
Обновился? 
Коне...
24 
Загрузка одного тайла 
NetTileProvider 
Один сырой тайл 
Запрос одной версии 
тайла из сети 
RawTileLoader 
Кешировани...
25 
RawTileLoader 
Задача – вернуть поток версий сырых данных 
MultiFuture<RawTile> rawTileVersions(int x, y) {! 
return a...
26 
TileLoader 
Задача – вернуть поток версий одного тайла 
MultiFuture<Tile> tileVersions(int x, y) {! 
return async<Tile...
27 
Линейный код из примера 
void loadTile(int x, int y, output_iterator output) {! 
if (auto tile = inMemory(x, y)) {! 
o...
28 
Мы пишем понятный и выразительный код 
И вам желаем того жеJ
29 
Спасибо за внимание!
30 
Дмитрий Жестилевский 
Яндекс.Карты 
Руководитель группы 
gordon@yandex-team.ru 
@dr_zhest
Upcoming SlideShare
Loading in …5
×

Дмитрий Жестилевский — Yet another threading framework: асинхронная разработка на C++ под мобильные устройства

760 views

Published on

Код приложений для мобильных устройств, написанный на C++, часто оказывается сложнее аналогичного на Java, ObjC или C#. Данные языки предлагают решения стандартных задач разработчика «из коробки». Многие из этих задач связаны с асинхронным выполнением операций.

В докладе я представлю подход к написанию понятного и производительного асинхронного кода на С++, который применяется в разработке библиотек для мобильных геоприложений в Яндексе.

Published in: Technology
0 Comments
0 Likes
Statistics
Notes
  • Be the first to comment

  • Be the first to like this

No Downloads
Views
Total views
760
On SlideShare
0
From Embeds
0
Number of Embeds
406
Actions
Shares
0
Downloads
5
Comments
0
Likes
0
Embeds 0
No embeds

No notes for slide

Дмитрий Жестилевский — Yet another threading framework: асинхронная разработка на C++ под мобильные устройства

  1. 1. 1
  2. 2. 2 карты Асинхронная разработка на C++ Дмитрий Жестилевский
  3. 3. 3 Содержание ! Как работает загрузка карты ! Стейт-машина и линейный код ! С++11 concurrency ! Наш вариант concurrency ! Пример реализации загрузки карты
  4. 4. 4
  5. 5. 5 Тайл ! Можно отменять ! Должен кешироваться ! Должен обновляться ! Один тайл может содержать множество версий
  6. 6. 6 Схема загрузки одного тайла Старт Есть в памяти? Сходить в диск Есть на диске? Сходить в сеть Обновился? Конец Вернуть тайл Декодировать и положить в память Вернуть тайл Вернуть тайл Декодировать и положить в память Нет Да Да Да Нет Нет
  7. 7. 7 Конечный автомат Он же стейт-машина
  8. 8. Row<NotInRam , RequestTile , LoadingFromDisk , none , none >,! Row<NotInRam , DiscardTile , none , none , none >,! Row<NotInRam , UpdateTile , none , none , none >,! // +-------------+--------------------------+-----------------+-------------------+-----------------------+! Row<LoadingFromDisk, RequestTile , none , none , none >,! // this transition will be performed if isTileUpToDate returns false! Row<LoadingFromDisk, TileReady , UpdatingFromNet , NotifyCaller , none >,! Row<LoadingFromDisk, TileReady , UpToDateInRam , NotifyCaller , IsTileUpToDate >,! Row<LoadingFromDisk, TileRequestError , LoadingFromNet , none , none >,! // +-------------+--------------------------+-----------------+-------------------+-----------------------+! Row<LoadingFromNet , RequestTile , none , none , none >,! Row<LoadingFromNet , TileReady , InRamSyncing , NotifyCaller , none >,! Row<LoadingFromNet , TileRequestError , NotInRam , NotifyCaller , none >,! // +-------------+--------------------------+-----------------+-------------------+-----------------------+! Row<UpdatingFromNet, RequestTile , none , NotifyCaller , none >,! Row<UpdatingFromNet, TileReady , InRamSyncing , NotifyCaller , none >,! Row<UpdatingFromNet, TileRequestError , OldInRam , none , none >,! // +-------------+--------------------------+-----------------+-------------------+-----------------------+! Row<InRamSyncing , RequestTile , none , NotifyCaller , none >,! Row<InRamSyncing , DiscardTile , none , none , none >,! Row<InRamSyncing , TileSyncingCompleted , UpToDateInRam , none , none >,! Row<InRamSyncing , TileSyncingError , UpToDateInRam , none , none >,! // +-------------+--------------------------+-----------------+-------------------+-----------------------+! // May be we don't need this state.! Row<OldInRam , RequestTile , UpdatingFromNet , NotifyCaller , none >,! Row<OldInRam , UpdateTile , UpdatingFromNet , none , none >,! Row<OldInRam , DiscardTile , none , none , none >,! // +-------------+--------------------------+-----------------+-------------------+-----------------------+! Row<UpToDateInRam , RequestTile , none , NotifyCaller , none >,! Row<UpToDateInRam , UpdateTile , none , none , none >,! Row<UpToDateInRam , UpdateTile , UpdatingFromNet , none , Not_<IsTileUpToDate> >,! Row<UpToDateInRam , DiscardTile , none , none , none >,! // +-------------+--------------------------+-----------------+-------------------+-----------------------+! Row<AllOk , DiscardTile , CancelledMode , none , none >,! Row<CancelledMode , RequestTile , AllOk , none , none >! 8
  9. 9. 9 Линейный код void loadTile(int x, int y, output_iterator output) {! if (auto tile = inMemory(x, y)) {! output << tile;! }! ! if (auto tile = readFromDisk(x, y)) {! output << decode(tile);! prevVersion = tile.version;! }! ! while (true) {! Tile tile = readFromNet(x, y, prevVersion);! if (tile.version == prevVersion) continue;! prevVersion = tile.version;! output << decode(tile);! }! }! !
  10. 10. 10 C++11 concurrency
  11. 11. Promise<int> promise;! 11 Future/Promise Promise<int> p;! Future<int> f = p.future();! Future Promise auto future = startAsync();! // ...! // ...! int value = future.get();! int val = calc();! std::cout << value;!promise.set(val);!
  12. 12. 12 Использование Future output int meaningOfLife() {! sleep(100500);! return 42;! }! ! int main() {! std::future<int> meaningOfLife = std::async([] { ! return meaningOfLife(); ! });! ! std::future<int> calculation = std::async([] { return calcSmth(); });! ! std::cout << meaningOfLife().get() + calculation.get() << std::endl;! }! { calcSmth Meaning Of Life }
  13. 13. 13 std::async Пример реализации std::async в случае создания отдельного потока на каждую операцию Future<T> async(Function<T()> func) {! Promise<T> promise;! auto future = promise.future();! ! std::thread([promise = std::move(promise), func] {! try {! promise.setValue(func());! } catch (...) {! promise.setException(std::current_exception());! }! }).detach();! ! return future;! }!
  14. 14. 14 IO binding Использование асинхронной сети в синхронном коде void NetworkingAPI::httpGet(std::string url, ! std::function<void(Response, Error)>);! ! Future<Response> httpGet(const std::string& url) {! Promise<Response> promise;! auto future = promise.future();! ! NetworkingAPI::httpGet(url, ! [promise = std::move(promise)]! (Response response, Error error) {! if (error)! promise.setException(error);! else! promise.setValue(response);! });! }!
  15. 15. 15 Чего нет в std:: ! Масштабируемость ! Отменяемость асинхронных операций ! Генераторы — функции, возвращающие множество результатов
  16. 16. 16 Контексты исполнения ! Потоки ! Процессы
  17. 17. 17 Coroutine – user-space thread Пишем асинхронный код синхронно
  18. 18. 18 Примитивы async::Future! async::Promise! async::Mutex! async::CV! Coroutines! Coro Scheduler! std::future! std::promise! std::mutex! std::cv! Threads! OS Scheduler! Future.get() не блокирует поток Реализованы ~одинаково
  19. 19. 19 Модель потоков Все взаимодействие с IO – в отдельных выделенных потоках (сеть, диск) Все остальное – в глобальном thread pool
  20. 20. 20 Отмена операций ! Отмена через exception (Future.reset, ~Future) ! Cancellation points: wait, sleep, get ! Мгновенная отмена или ленивая?
  21. 21. 21 Генераторы
  22. 22. 22 Поточная десериализация Генератор1: байты Генератор2: байты объекты MultiFuture<char> networkBytes();! ! MultiFuture<Object> objects(MultiFuture<char> bytesStream) {! return async<Object>([](MultiPromise<Object>* output) {! Parser parser(std::move(bytesStream));! ! while (!parser.finished()) {! output->yield(parser.next());! }! };! }! ! void Parser::read(int size, char* data) {! while (size > 0) {! *data = bytes_.get();! data++; ! size--;! }! }! !
  23. 23. 23 Схема загрузки одного тайла Старт Есть в памяти? Сходить в диск Есть на диске? Сходить в сеть Обновился? Конец Вернуть тайл Декодировать и положить в память Вернуть тайл Вернуть тайл Декодировать и положить в память Нет Да Да Да Нет Нет
  24. 24. 24 Загрузка одного тайла NetTileProvider Один сырой тайл Запрос одной версии тайла из сети RawTileLoader Кеширование на диске Версионирование Поток версий сырых данных TileLoader Кеширование в памяти Декодирование Поток версий готовых тайлов
  25. 25. 25 RawTileLoader Задача – вернуть поток версий сырых данных MultiFuture<RawTile> rawTileVersions(int x, y) {! return async<RawTile>([=](MultiPromise<RawTile>* output) {! std::string currentVer, currentEtag;! RawTile rawTile;! ! if (rawTile = readFromDisk(x, y)) {! currentVer = rawTile->version;! currentEtag = rawTile->etag;! output->yield(rawTile);! }! ! for (const auto& ver : versions_.subscribe()) {! rawTile = loadFromNetwork(x, y, ver, currentEtag);! ! writeToDisk(x, y, rawTile);! ! currentVer = rawTile->version;! currentEtag = rawTile->etag;! output->yield(rawTile);! } ! }); // async! }!
  26. 26. 26 TileLoader Задача – вернуть поток версий одного тайла MultiFuture<Tile> tileVersions(int x, y) {! return async<Tile>([=](MultiPromise<Tile>* output) {! Tile tile = memCache->get(x, y);! if (tile) ! output->yield(tile);! ! for (const auto& rawTile : rawTileVersions(x, y)) {! tile.version = rawTile->version;! if (tile.etag != rawTile->etag) {! tile.etag = rawTile->etag;! tile.data = decoder_(rawTile->rawData);! }! ! output->yield(tile);! memCache_->set(x, y, tile);! }! }); // async! }!
  27. 27. 27 Линейный код из примера void loadTile(int x, int y, output_iterator output) {! if (auto tile = inMemory(x, y)) {! output << tile;! }! ! if (auto tile = readFromDisk(x, y)) {! output << decode(tile);! prevVersion = tile.version;! }! ! while (true) {! Tile tile = readFromNet(x, y, prevVersion);! if (tile.version == prevVersion) continue;! prevVersion = tile.version;! output << decode(tile);! }! }! !
  28. 28. 28 Мы пишем понятный и выразительный код И вам желаем того жеJ
  29. 29. 29 Спасибо за внимание!
  30. 30. 30 Дмитрий Жестилевский Яндекс.Карты Руководитель группы gordon@yandex-team.ru @dr_zhest

×