Рекомендуем использовать Visual Studio 2017

Пошаговое руководство. Реализация фьючерсов

 

Самая актуальная документация по Visual Studio 2017: Документация по Visual Studio 2017.

В этом разделе показано, как реализовывать futures в приложении. Разделе показано, как объединить существующие функциональные возможности среды выполнения с параллелизмом в нечто дополнительных.

System_CAPS_ICON_important.jpg Важно

В этом разделе рассматривается понятие фьючерсов для демонстрационных целей. Мы рекомендуем использовать std::future или concurrency::task Если требуется асинхронная задача, которая вычисляет значение для последующего использования.

A задачи является вычисление, которое можно разложить на дополнительные, более мелкие вычисления. A будущих — это асинхронная задача, которая вычисляет значение для последующего использования.

Для реализации фьючерсов в этом разделе определяется async_future класса. async_future Эти компоненты среды выполнения с параллелизмом использует класс: concurrency::task_group класса и concurrency::single_assignment класса. async_future Класс использует task_group класса для асинхронного вычисления значения и single_assignment класса для хранения результата вычисления. Конструктор async_future класса принимает рабочую функцию, которая вычисляет результат, и get метод извлекает результат.

Реализация класса async_future

  1. Объявите шаблонный класс с именем async_future параметризованный по типу результирующего вычисления. Добавление public и private разделы к этому классу.

template <typename T>
class async_future
{
public:
private:
};

  1. В private разделе async_future объявите task_group и single_assignment элемента данных.

   // Executes the asynchronous work function.
   task_group _tasks;

   // Stores the result of the asynchronous work function.
   single_assignment<T> _value;

  1. В public разделе async_future класса, реализуйте конструктор. Конструктор — это шаблон, параметризованный по рабочей функции, вычисляющей результат. Конструктор асинхронно выполняет рабочую функцию в task_group данных и использует concurrency::send функции для записи результата в single_assignment элемент данных.

   template <class Functor>
   explicit async_future(Functor&& fn)
   {
      // Execute the work function in a task group and send the result
      // to the single_assignment object.
      _tasks.run([fn, this]() {
         send(_value, fn());
       });
   }

  1. В public разделе async_future следует реализовать деструктор. Деструктор ожидает завершения выполнения задачи.

   ~async_future()
   {
      // Wait for the task to finish.
      _tasks.wait();
   }

  1. В public разделе async_future следует реализовать get метод. Этот метод использует concurrency::receive функции для извлечения результата рабочей функции.

   // Retrieves the result of the work function.
   // This method blocks if the async_future object is still 
   // computing the value.
   T get()
   { 
      return receive(_value); 
   }

Описание

В следующем примере показано полное async_future класс и пример его использования. wmain Функция создает std::вектор объект, содержащий 10000 случайных целых чисел. Затем он использует async_future объектов найти наименьшее и наибольшее значения, содержащиеся в vector объекта.

Код

// futures.cpp
// compile with: /EHsc
#include <ppl.h>
#include <agents.h>
#include <vector>
#include <algorithm>
#include <iostream>
#include <numeric>
#include <random>

using namespace concurrency;
using namespace std;

template <typename T>
class async_future
{
public:
   template <class Functor>
   explicit async_future(Functor&& fn)
   {
      // Execute the work function in a task group and send the result
      // to the single_assignment object.
      _tasks.run([fn, this]() {
         send(_value, fn());
       });
   }

   ~async_future()
   {
      // Wait for the task to finish.
      _tasks.wait();
   }

   // Retrieves the result of the work function.
   // This method blocks if the async_future object is still 
   // computing the value.
   T get()
   { 
      return receive(_value); 
   }

private:
   // Executes the asynchronous work function.
   task_group _tasks;

   // Stores the result of the asynchronous work function.
   single_assignment<T> _value;
};

int wmain()
{
   // Create a vector of 10000 integers, where each element 
   // is between 0 and 9999.
   mt19937 gen(2);
   vector<int> values(10000);   
   generate(begin(values), end(values), [&gen]{ return gen()%10000; });

   // Create a async_future object that finds the smallest value in the
   // vector.
   async_future<int> min_value([&]() -> int { 
      int smallest = INT_MAX;
      for_each(begin(values), end(values), [&](int value) {
         if (value < smallest)
         {
            smallest = value;
         }
      });
      return smallest;
   });
   
   // Create a async_future object that finds the largest value in the
   // vector.
   async_future<int> max_value([&]() -> int { 
      int largest = INT_MIN;
      for_each(begin(values), end(values), [&](int value) {
         if (value > largest)
         {
            largest = value;
         } 
      });
      return largest;
   });

   // Calculate the average value of the vector while the async_future objects
   // work in the background.
   int sum = accumulate(begin(values), end(values), 0);
   int average = sum / values.size();

   // Print the smallest, largest, and average values.
   wcout << L"smallest: " << min_value.get() << endl
         << L"largest:  " << max_value.get() << endl
         << L"average:  " << average << endl;
}

Комментарии

В этом примере выводятся следующие данные:

smallest: 0  
largest:  9999  
average:  4981  

В примере используется async_future::get метод для извлечения результатов вычисления. async_future::get Метод ожидает завершения, если вычисление еще выполняется вычисления.

Для расширения async_future класса обрабатывал исключения, вызываемые рабочей функцией, измените async_future::get метод для вызова Concurrency::task_group:: wait метод. task_group::wait Метод создает все исключения, возникшие в рабочей функции.

В следующем примере показано измененная версия async_future класса. wmain Функция использует try-catch блока для печати результата async_future объекта или для печати значения исключение, которое создается в рабочей функции.

// futures-with-eh.cpp
// compile with: /EHsc
#include <ppl.h>
#include <agents.h>
#include <vector>
#include <algorithm>
#include <iostream>

using namespace concurrency;
using namespace std;

template <typename T>
class async_future
{
public:
   template <class Functor>
   explicit async_future(Functor&& fn)
   {
      // Execute the work function in a task group and send the result
      // to the single_assignment object.
      _tasks.run([fn, this]() {
         send(_value, fn());
       });
   }

   ~async_future()
   {
      // Wait for the task to finish.
      _tasks.wait();
   }

   // Retrieves the result of the work function.
   // This method blocks if the async_future object is still
   // computing the value.
   T get()
   { 
      // Wait for the task to finish.
      // The wait method throws any exceptions that were generated
      // by the work function.
      _tasks.wait();

      // Return the result of the computation.
      return receive(_value);
   }

private:
   // Executes the asynchronous work function.
   task_group _tasks;

   // Stores the result of the asynchronous work function.
   single_assignment<T> _value;
};

int wmain()
{
   // For illustration, create a async_future with a work 
   // function that throws an exception.
   async_future<int> f([]() -> int { 
      throw exception("error");
   });

   // Try to read from the async_future object. 
   try
   {
      int value = f.get();
      wcout << L"f contains value: " << value << endl;
   }
   catch (const exception& e)
   {
      wcout << L"caught exception: " << e.what() << endl;
   }
}

В этом примере выводятся следующие данные:

caught exception: error  

Дополнительные сведения о модели обработки исключений в среде выполнения с параллелизмом см. в разделе Обработка исключений.

Скопируйте код примера и вставьте его в проект Visual Studio и вставьте его в файл с именем futures.cpp и затем выполните следующую команду в окне командной строки Visual Studio.

CL.exe/EHsc futures.cpp

Примеры выполнения параллелизма
Обработка исключений
Класс task_group
Класс single_assignment

Показ: