Compartir a través de


Tutorial: Implementar futuros

En este tema se muestra cómo implementar futuros en la aplicación.En el tema se muestra cómo combinar la funcionalidad existente en el Runtime de simultaneidad para conseguir algo que hace más.

Nota importanteImportante

Este tema ilustra el concepto de futuros para la demostración.Le recomendamos que utilice std::future o concurrency::task cuando se requiere una tarea asincrónica que calcula un valor para su uso posterior.

Una tarea es un cálculo que se puede descomponer en otros cálculos más específicos.Un futuro es una tarea asincrónica que calcula un valor para su uso posterior.

Para implementar futuros, este tema define la clase async_future.El async_future clase utiliza estos componentes en tiempo de ejecución de simultaneidad: el concurrency::task_group clase y el concurrency::single_assignment clase.La clase async_future utiliza la clase task_group para calcular un valor de forma asincrónica y la clase single_assignment para almacenar el resultado del cálculo.El constructor de la clase async_future toma una función de trabajo que calcula el resultado, y el método get recupera el resultado.

Para implementar la clase async_future

  1. Declare una clase de plantilla con el nombre async_future que se parametrice en el tipo del cálculo resultante.Agregue secciones public y private a esta clase.

    template <typename T>
    class async_future
    {
    public:
    private:
    };
    
  2. En la sección private de la clase async_future, declare miembros de datos task_group y single_assignment.

    // Executes the asynchronous work function.
    task_group _tasks;
    
    // Stores the result of the asynchronous work function.
    single_assignment<T> _value;
    
  3. En la sección public de la clase async_future, implemente el constructor.El constructor es una plantilla que se parametriza en la función de trabajo que calcula el resultado.El constructor asincrónica ejecuta la función de trabajo en el task_group miembro de datos y se utiliza el concurrency::send función para escribir el resultado a la single_assignment miembro de datos.

    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. En la sección public de la clase async_future, implemente el destructor.El destructor espera hasta que finaliza la tarea.

    ~async_future()
    {
       // Wait for the task to finish.
       _tasks.wait();
    }
    
  5. En la sección public de la clase async_future, implemente el método get.Este método utiliza el concurrency::receive función para recuperar el resultado de la función de trabajo.

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

Ejemplo

Dd764564.collapse_all(es-es,VS.110).gifDescripción

En el siguiente ejemplo se muestran la clase async_future completa y un ejemplo de su uso.La función wmain crea un objeto std::vector que contiene 10.000 valores enteros aleatorios.A continuación, utiliza objetos async_future para encontrar los valores mayor y menor incluidos en el objeto vector.

Dd764564.collapse_all(es-es,VS.110).gifCódigo

// 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(es-es,VS.110).gifComentarios

Este ejemplo produce el siguiente resultado.

smallest: 0
largest:  9999
average:  4981

En el ejemplo se usa el método async_future::get para recuperar los resultado del cálculo.El método async_future::get espera hasta que finaliza el cálculo si este está todavía activo.

Programación sólida

Para ampliar el async_future clase para controlar las excepciones que se producen por la función de trabajo, modifique la async_future::get método para llamar a la concurrency::task_group::wait método.El método task_group::wait inicia las excepciones que genera la función de trabajo.

En el ejemplo siguiente se muestra la versión modificada de la clase async_future:La función wmain utiliza un bloque try-catch para imprimir el resultado del objeto async_future o imprimir el valor de la excepción que genera la función de trabajo.

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

Este ejemplo produce el siguiente resultado.

caught exception: error

Para obtener más información sobre el modelo de control de excepciones en el Runtime de simultaneidad, vea Control de excepciones en el runtime de simultaneidad.

Compilar el código

Copie el código de ejemplo y péguelo en un proyecto de Visual Studio o lo pega en un archivo denominado futures.cpp y, a continuación, ejecute el siguiente comando en una ventana de símbolo del sistema de Visual Studio.

cl.exe /EHsc futures.cpp

Vea también

Referencia

task_group (Clase)

Clase single_assignment

Conceptos

Control de excepciones en el runtime de simultaneidad

Otros recursos

Tutoriales del Runtime de simultaneidad