Freigeben über


Exemplarische Vorgehensweise: Implementieren von Futures

In diesem Thema erfahren Sie, wie Sie Futures in Ihre Anwendung implementieren.Es wird veranschaulicht, wie Sie die vorhandenen Funktionen in der Concurrency Runtime kombinieren können, um mehr Funktionalität zu erzielen.

Wichtiger HinweisWichtig

Dieses Thema veranschaulicht das Konzept der Futures zu Demonstrationszwecken.Wir empfehlen die Verwendung std::future oder concurrency::task Wenn Sie eine asynchrone Aufgabe, die einen Wert für die spätere Verwendung berechnet erfordern.

Eine Aufgabe ist eine Berechnung, die in weitere, differenziertere Berechnungen unterteilt werden kann.Ein Future ist eine asynchrone Aufgabe zur Berechnung eines Werts für die spätere Verwendung.

Zur Implementierung von Futures wird in diesem Thema die async_future-Klasse definiert.Die async_future -Klasse verwendet diese Komponenten der Parallelität Runtime: die concurrency::task_group Klasse und die concurrency::single_assignment Klasse.Die async_future-Klasse verwendet die task_group-Klasse zur asynchronen Berechnung eines Werts und die single_assignment-Klasse zum Speichern des Ergebnisses.Der Konstruktor der async_future-Klasse akzeptiert eine Arbeitsfunktion, die das Ergebnis berechnet, das mit der get-Methode abgerufen wird.

Implementieren die Async_future-Klasse

  1. Deklarieren Sie eine Vorlagenklasse mit dem Namen async_future, die auf der Grundlage des Typs der resultierenden Berechnung parametrisiert wird.Fügen Sie der Klasse einen public-Abschnitt und einen private-Abschnitt hinzu.

    template <typename T>
    class async_future
    {
    public:
    private:
    };
    
  2. Deklarieren Sie im private-Abschnitt der async_future-Klasse ein task_group-Datenmember und ein single_assignment-Datenmember.

    // Executes the asynchronous work function.
    task_group _tasks;
    
    // Stores the result of the asynchronous work function.
    single_assignment<T> _value;
    
  3. Implementieren Sie im public-Abschnitt der async_future-Klasse den Konstruktor.Der Konstruktor ist eine Vorlage, die auf Grundlage der Arbeitsfunktion, die zur Berechnung des Ergebnisses dient, parametrisiert wird.Der Konstruktor asynchron ausgeführt, wird die Arbeit-Funktion in der task_group Datenmember und verwendet die concurrency::send Funktion, um das Ergebnis zu schreiben der single_assignment Datenmember.

    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());
        });
    }
    
  4. Implementieren Sie im public-Abschnitt der async_future-Klasse den Destruktor.Der Destruktor wartet auf das Beenden der Aufgabe.

    ~async_future()
    {
       // Wait for the task to finish.
       _tasks.wait();
    }
    
  5. Implementieren Sie im public-Abschnitt der async_future-Klasse die get-Methode.Diese Methode verwendet die concurrency::receive Funktion zum Abrufen des Ergebnisses der Funktion arbeiten.

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

Beispiel

Dd764564.collapse_all(de-de,VS.110).gifBeschreibung

Das folgende Beispiel zeigt die vollständige async_future-Klasse mit einer Verwendungsmöglichkeit.Die wmain-Funktion erstellt ein std::vector-Objekt, das 10.000 zufällige Ganzzahlwerte enthält.Anschließend werden mithilfe von async_future-Objekten der kleinste und der größte Wert im vector-Objekt gesucht.

Dd764564.collapse_all(de-de,VS.110).gifCode

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

Dd764564.collapse_all(de-de,VS.110).gifKommentare

Dieses Beispiel erzeugt folgende Ausgabe:

smallest: 0
largest:  9999
average:  4981

Im Beispiel werden die Ergebnisse der Berechnung mit der async_future::get-Methode abgerufen.Die async_future::get-Methode wartet, bis die Berechnung beendet ist.

Stabile Programmierung

Erweitern der async_future Klasse zum Behandeln von Ausnahmen, die von der Arbeit-Funktion ausgelöst werden, ändern die async_future::get -Methode aufrufen, die Concurrency::task_group::wait Methode.Die task_group::wait-Methode löst alle von der Arbeitsfunktion generierten Ausnahmen aus.

Das folgende Beispiel zeigt die geänderte Version der async_future-Klasse.Die wmain-Funktion verwendet einen try-catch-Block, um das Ergebnis des async_future-Objekts bzw. den Wert der von der Arbeitsfunktion generierten Ausnahme auszugeben.

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

Dieses Beispiel erzeugt folgende Ausgabe:

caught exception: error

Weitere Informationen zum Ausnahmebehandlungsmodell in der Concurrency Runtime finden Sie unter Ausnahmebehandlung in der Concurrency Runtime.

Kompilieren des Codes

Kopieren Sie den Beispielcode und fügen Sie ihn in ein Visual Studio Projekt, oder fügen Sie ihn in eine Datei mit dem Namen futures.cpp und führen Sie den folgenden Befehl in ein Visual Studio-Eingabeaufforderungsfenster.

cl.exe /EHsc futures.cpp

Siehe auch

Referenz

task_group-Klasse

single_assignment-Klasse

Konzepte

Ausnahmebehandlung in der Concurrency Runtime

Weitere Ressourcen

Exemplarische Vorgehensweisen für die Concurrency Runtime