Upgrade to Pro — share decks privately, control downloads, hide ads and more …

Как сделать свой Future-Promise или жизненный ц...

Как сделать свой Future-Promise или жизненный цикл велосипедов в продакшене

Build your own Future, they said.
It will worth the hassle, they Promised.
That is how I should Function, I was told.
It is the main Task of my life, prophecy declared.

Avatar for Denis Kormalev

Denis Kormalev

May 24, 2018
Tweet

More Decks by Denis Kormalev

Other Decks in Programming

Transcript

  1. Жизненный цикл велосипедов в продакшене Build your own Future, they

    said. It will worth the hassle, they Promised. That is how I should Function, I was told. It is the main Task of my life, prophecy declared. Денис Кормалев Санкт-Петербург, 2018
  2. Темные Века • 3-4 проекта, использующих одинаковые механизмы и планы

    на еще два десятка (перенос использующихся решений с легаси) • Постоянное обновление общих механизмов • Основная логика основана на сочетании информации от разных веб-сервисов • Основной веб-сервис (90% всех данных) очень медленный • Нередко можно забирать данные с нескольких сервисов (или даже от одного сервиса) одновременно, не дожидаясь других ответов • Очень много однообразного кода на обслуживание работы с ответами от сервисов
  3. Средние Века • Свой фреймворк, основанный, в том числе, на

    таск шедулере • Шедулер: • Выполняет задачи в фоновых потоках • Позволяет из одного таска вызвать другой или другие • Позволяет ждать таск • Позволяет ожидать асинхронные вызовы, которые присылают ответ через сигнал • Абсолютное большинство данных на бекенде – через shared pointer или Qt контейнеры
  4. Реализация • addTask использует std::async, все std::future хранятся в мапе

    и обслуживаются дополнительным потоком • touchTask реализован через краткое (1мс) ожидание • addSignalWaiter/fireSignalWaiter используют thread_local евент лупы • fireSignalWaiter запускает евент луп • addSignalWaiter подключает сигнал к обертке над пользовательским слотом, которая, если слот вернул true, закрывает евент луп
  5. Минусы • Все еще прилично бойлерплейта • Нет ограничения в

    количестве потоков • На каждый таск создается новый поток • Дополнительные потоки для обслуживания • std::async + std::future приводят к дополнительным проблемам • Возвращать ошибки не то, чтобы очень легко • Возвращать данные тоже • При параллелизации приходится городить излишние структуры
  6. Future • Свой future: • Монада • Иммутабельность • Не

    требует дополнительной поддержки • Нужно упростить работу с возвратом результатов и ошибок • Нужно уменьшить количество лишнего кода для описания логики • Нужно перейти на пул потоков • Слишком мало багов осталось в коде за три с лишним года работы TaskChain, нужны новые
  7. Возвращение Ошибки • Errno • Нет, спасибо, просто нет •

    if err != nil • Все еще спасибо, нет • Exceptions • Оверхед при использовании • Исключения для исключительных ситуаций, не для управления выполнением программы • Either • Уже лучше, но приведет к слишком большому объему кода • EitherT • Наш кандидат*
  8. Не хватает • Преобразование значения • map • filter •

    Монада • successful/failure • flatMap • Восстановление после ошибок • recover • recoverWith • Связывание фьючеров • zip • sequence
  9. Шедулинг • Пул потоков • Backpressure • На каждое добавление

    таска – пытаемся шедулить • На каждое завершение таска – пытаемся шедулить • Пока нет тасков – спим в wait condition • Треды в пуле создаются, пока не достигли максимума • Запуск таска возвращает Future • Возможность создания подпулов
  10. RestrictionType • enum class RestrictionType { Custom, Intensive, ThreadBound };

    • Custom – отдельные подпулы с задаваемым пользователем лимитом • Intensive – подпул, ограниченный по количеству ядер • ThreadBound – гарантирует что все таски с одинаковым лейблом будут запущены в одном потоке
  11. Cancelable • Возможность передачи намерения отмены • Без 100% гарантии

    отмены • Отмена действия только до преобразований • Иначе нарушается гарантия иммутабельности преобразований • Минимальная синтаксическая нагрузка при неиспользовании