Návod: Implementace tříd future

Toto téma ukazuje, jak implementovat budoucnost ve vaší aplikaci. Toto téma ukazuje, jak zkombinovat existující funkce v modulu Concurrency Runtime do něčeho, co dělá víc.

Důležité

Toto téma ukazuje koncept futures pro demonstrační účely. Doporučujeme použít std::future nebo concurrency::task , pokud potřebujete asynchronní úlohu, která vypočítá hodnotu pro pozdější použití.

Úkol je výpočet, který lze rozdělit do dalších, jemněji odstupňovaných výpočtů. Budoucnost je asynchronní úloha, která vypočítá hodnotu pro pozdější použití.

Chcete-li implementovat futures, toto téma definuje async_future třídu. Třída async_future používá tyto komponenty Concurrency Runtime: concurrency::task_group třídy a concurrency::single_assignment třída. Třída async_future používá task_group třídu k asynchronnímu výpočtu hodnoty a single_assignment třídy k uložení výsledku výpočtu. Konstruktor async_future třídy přebírá pracovní funkci, která vypočítá výsledek a get metoda načte výsledek.

Implementace třídy async_future

  1. Deklarujte třídu šablony s názvem async_future , která je parametrizována pro typ výsledného výpočtu. Přidejte public do private této třídy oddíly.
template <typename T>
class async_future
{
public:
private:
};
  1. private V části async_future třídy deklarujte task_group a single_assignment datový člen.
// Executes the asynchronous work function.
task_group _tasks;

// Stores the result of the asynchronous work function.
single_assignment<T> _value;
  1. public V části async_future třídy implementujte konstruktor. Konstruktor je šablona, která je parametrizována pro pracovní funkci, která vypočítá výsledek. Konstruktor asynchronně spustí pracovní funkci v datovém členu task_group a použije funkci concurrency::send k zápisu výsledku do datového členu 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 V části async_future třídy implementujte destruktor. Destruktor čeká na dokončení úkolu.
~async_future()
{
   // Wait for the task to finish.
   _tasks.wait();
}
  1. public V části async_future třídy implementujte metoduget. Tato metoda používá funkci concurrency::receive k načtení výsledku pracovní funkce.
// 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); 
}

Příklad

Popis

Následující příklad ukazuje úplnou async_future třídu a příklad jejího použití. Funkce wmain vytvoří objekt std::vector , který obsahuje 10 000 náhodných celočíselné hodnoty. Pak pomocí async_future objektů vyhledá nejmenší a největší hodnoty obsažené v objektu vector .

Kód

// 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;
}

Komentáře

Tento příklad vytvoří následující výstup:

smallest: 0
largest:  9999
average:  4981

Příklad používá metodu async_future::get k načtení výsledků výpočtu. Metoda async_future::get čeká na dokončení výpočtu, pokud je výpočet stále aktivní.

Robustní programování

Chcete-li rozšířit async_future třídu tak, aby zpracovávala výjimky vyvolané pracovní funkcí, upravte async_future::get metodu tak, aby volala metodu concurrency::task_group::wait metoda. Metoda task_group::wait vyvolá všechny výjimky, které byly generovány pracovní funkcí.

Následující příklad ukazuje upravenou verzi async_future třídy. Funkce wmain používácatchtry-blok k tisku výsledku objektu async_future nebo k vytištění hodnoty výjimky, která je generována pracovní funkcí.

// 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;
   }
}

Tento příklad vytvoří následující výstup:

caught exception: error

Další informace o modelu zpracování výjimek v modulu Concurrency Runtime najdete v tématu Zpracování výjimek.

Probíhá kompilace kódu

Zkopírujte ukázkový kód a vložte ho do projektu sady Visual Studio nebo ho vložte do pojmenovaného futures.cpp souboru a potom v okně příkazového řádku sady Visual Studio spusťte následující příkaz.

cl.exe /EHsc futures.cpp

Viz také

Návody pro Concurrency Runtime
Zpracování výjimek
task_group – třída
single_assignment – třída