Главная
Блог разработчиков phpBB
 
+ 17 предустановленных модов
+ SEO-оптимизация форума
+ авторизация через соц. сети
+ защита от спама

Resumable функции

Anna | 24.06.2014 | нет комментариев

На прошлой неделе в мире С случилось увлекательное событие. Компания Microsoft объявила о выходе обновления к компилятору С в Visual Studio 2013. Само по себе обновление компилятора отдельно от Visual Studio либо её сервис-пака — теснее нетривиальное для Microsoft событие. Но ещё увлекательнее то, что вошло в это обновление. Полный список дозволено почитать по ссылке выше, а я остановлюсь только на одном моменте — resumable функции. Для полного понимания обстановки: Microsoft довольно протроллила и комитет по стандартизации С и разработчиков gcc\clang, выпустив (здесь нужно наблюдательно) реализацию экспериментальной и не утверждённой ещё вероятности грядущего эталона C 17, основанной на экспериментальных и не утверждённых ещё вероятностях грядущего эталона C 14, которые в свою очередь являются исправлениями не крепко ещё вошедших в повседневное программирование вероятностей С 11.

Довольно гиковский ход, не находите?

А ниже будет перевод статьи с meetingcpp.com, рассказывающей о том, что это за фича и как её применять.

На прошедшей незадолго конференции BUILD Херб Саттер рассказывал о грядущем языка С . Его отчет был полон прекрасных примеров на С 11 и С 14. И внезапно, прямо из ниотколе — resumable функции. Херб — один из авторов документа, описывающего std::future и resumable функции, так что само их припоминание не было для меня сюрпризом, но вот что меня поразило, так это то, сколько внимания он уделил этой теме и припоминание того факт, что resumable функции войдут в обновление к Visual Studio 2013 (пускай не в сам релиз VS2013, но всё же гораздо прежде дальнейшей версии IDE).

Я начну с небольшого спойлера: это вероятность как минимум С 1y, она не войдёт в С 14, но в последующем именно асинхронное и параллельное программирование будет в тренде становления языка, так что resumable функции станут органичной частью нового эталона. В последующем эта фича будет поддерживаться всеми компиляторами, а на данный момент Microsoft шагает впереди планеты каждой с собственной реализацией. Не секрет, что данная функциональность имеет некоторую параллель с async/await из языка C#.

Что такое resumable функции?

Это, вообще-то и есть основной вопрос, тот, что мы здесь пытаемся узнать. Раньше чем я начну пояснять, чем бы это могло быть и как их определяет документ N3650, я должен сделать небольшую остановку и рассказать, что такое futures, от того что resumable функции основаны на том предположении, что std::future будет расширено способом .then(), как это предполагается в документе N3634. future — это итог выполнения асинхронной операции. Это одно из базовых представлений асинхронного программирования. future — это место, где хранится информация о ранге выполнения асинхронной задачи и её итог, если он теснее доступен. Вы можете вызывать способ get(), тот, что дождётся заключения асинхронной операции и вернёт вам её итог (это теснее реализовано в эталоне), либо зарегистрировать обработчик её заключения через способ .then() (тот, что пока что не в эталоне). Неимение .then() в С 11 — одна из особенно критикуемых ошибок, она наверно будет поправлена в С 14, совместно с некоторыми другими совершенствованиями std::future.

С 11 добавил в С лямбды, так что в комбинации это даёт вероятность возвести цепочку асинхронных вызовов лямбда-функций (колбеков). Сейчас будет допустимо запустить выполнение асинхронной задачи и отреагировать на её заключение в обработчике, зарегистрированном через способ .then(). «Прочитать результат сервера, then — распарсить его, then — обработать его, …». С проверкой ошибок и логированием по ходу дела. Такой подход является обыденным делом в некоторых языках, но пока не в С . Верное осознавание столь сильного механизма может серьёзно повлиять на то, как вы будете писать код в грядущем.

Короткий пример, Дабы продемонстрировать std::future:

std::future<int> f_int = make_dummy_future(42);
int i = f_int.get() // ждём окончания работы функции
f_int.then([](std::future<int> i){/* deal with it */}) // регистрируем обработчик

Идея resumable функции в том, Дабы дозволить компилятору самому позаботиться о построении цепочки futures, присоединённых друг к другу, и верном их вызове через .then().
Достичь этогk!/h5>
Скорость и эффективность — не исключительное (а может быть даже и не основное) в resumable функциях. Больше славное — сам их синтаксис, его легкость, простота и изящность. Вы можете легко начать писать код с применением async/await, наравне с базовыми конструкциями языка типа (if/else, for и т.д.). Код становится чище. Вот пример из документа N3650, в начале с применением только std::future:

future<int> f(shared_ptr str)
{
  shared_ptr<vector> buf = ...;
  return str->read(512, buf)
  .then([](future<int> op)// lambda 1
  {
    return op.get()   11;
  });
}

future<void> g()
{
  shared_ptr s = ...;
  return f(s).then([s](future<int> op) // lambda 2
  {
  s->close();
  });
} 

А сейчас напишем то же самое на resumable функциях:

future<void> f(stream str) async
{
  shared_ptr<vector> buf = ...;
  int count = await str.read(512, buf);
  return count   11;
}

future g() async
{
  stream s = ...;
  int pls11 = await f(s);
  s.close();
}

Код с resumable функциями стал короче и гораздо отменнее читаемым (что, на самом деле, самое значимое в коде). Но реальные превосходства начинают проявляться когда асинхронный код комбинируется с базовыми руководящими элементами языка. Я покажу вам короткий пример, тот, что привел Herb Sutter в своём докладе на BUILD:

std::string read( std::string file, std::string suffix ) {
   std::istream fi = open(file).get();
   std::string ret, chunk;
   while( (chunk = fi.read().get()).size() )
      ret  = chunk   suffix;
   return ret;
}

Это примитивный пример «синхронной асинхронности» — в коде применяется future::get() Дабы дождаться итога асинхронной операции в std::future. Хорошо было бы усовершенствовать и ускорить данный код, заменив get() на then(). Давайте посмотрим, что выйдет.

task<std::string> read( std::string file, std::string suffix ) {
   return open(file)
   .then([=](std::istream fi) {
      auto ret = std::make_shared<std::string>();
      auto next = 
         std::make_shared<std::function<task()>>(
      [=]{
         fi.read()
         .then([=](std::string chunk) {
            if( chunk.size() ) {
               *ret  = chunk   suffix;
               return (*next)();
            }
            return *ret;
         });
      });
      return (*next)();
   });
}

Для того Дабы применять .then() правильно нам пришлось слегка усложнить код. А сейчас давайте посмотрим как то же самое могло бы выглядеть на async/await:

task<std::string> read( std::string file, std::string suffix ) __async {
   std::istream fi = __await open(file);
   std::string ret, chunk;
   while( (chunk = __await fi.read()).size() )
      ret  = chunk   suffix;
   return ret;
}

В обоих случаях возвращаемое значение должно быть типа task<std::string>, от того что на момент возврата оно всё ещё может быть в процессе рассчёта. Версия с применением await гораздо проще, чем версия с .then(). Данная реализация использует ключевые слова __async и __await в том виде, в каком они будут добавлены в Visual Studio.

Давайте вернёмся к реальному коду. Вашей работой Зачастую будет его помощь, даже если его написал кто-то иной. Представьте себе цепочку из std::future, auto и .then выражений, с вкраплениями лямбда функций — скорее каждого это не то, на что вам хотелось бы глядеть всякий день. Но именно этим всё и закончится без resumable функций. Данный код не будет менее продуктивным, но вот время, которое вы потратите на его модификацию будет гораздо огромнее, чем в случае с примитивными и логичными async/await. С применением resumable функций компилятор берёт на себя массу отвлекающих деталей, заботится о корректности «границ» областей видимости, верно заворачивает итоги вызовов асинхронных функций в std::future, так что на данный момент счёт как минимум 1:0 в пользу resumable функций.

Идём дальше. Мы теснее узнали, что resumable функции добаляют изящества в код и делают вещи больше примитивными. Но довольно ли этого, Дабы вот прямо взять и изменить язык С ? Вряд ли. Обязаны быть и другие поводы. И они есть. Глядите — у нас есть 2 варианта: помощь на ярусе библиотек и помощь на ярусе языка. Если позабыть о красоте синтаксиса — эквивалентны ли они в остальном? Нет. Давайте предположим себе, каким образом может протекать отладка асинхронного кода. В случае применения библиотечного решения вопрос отладки стоит дюже остро. mk!/code>, s<T>& либо const s<T>. Значение этого параметра должно быть сразу же доступно способу get().

  • опциональный способ is_ready(), возвращающий состояние future

Дальше авторы рассуждают о том, что должен быть определён тип s<T>::promise_type, тот, что будет доступен реализации resumable функции. Данный тип должен предоставлять способы set_value(T) и set_exception(exception_ptr). Должно существовать неявное реформирование между s::promise_type и s.

Генераторы

Документ также включает в себя концепт, тот, что именуется «генераторная функция» либо легко «генератор». В STL имеются алгорифмы, дозволяющие применить некоторую функцию на все элементы контейнера, но они возвращают итог только по использованию ко каждому элементам контейнера, а генератор — возвращает итог непринужденно перед использованием к первому элементу. Тип возвращаемого значения — sequence<T> и тот, кто вызвал генератор, может применять это значения для итерирования по последовательности, которая будет создаваться по ходу итерирования (ленивые вычисления).

Для достижения этого результата предлагается ввести новое ключевое слово yield:

sequence<int> range(int low, int high) resumable
{
    for(int i = low; i <= high;   i)
    {
        yield i;
    }
}

yield будет вычислять значение i когда это потребуется при запросе к sequence. Всякая итерация поsequence<int> будет вызывать функцию, ждя получить дальнейший итог от yield. Тут не идёт речь о многопоточном либо асинхронном программировании — всё выполняется в одном потоке, но только лишь тогда, когда потребуется. Документ предлагает комбинировать в коде yield и await для достижения надобных программисту итогов.

Источник: programmingmaster.ru

Оставить комментарий
Форум phpBB, русская поддержка форума phpBB
Рейтинг@Mail.ru 2008 - 2017 © BB3x.ru - русская поддержка форума phpBB