Demonstra Passo a passo: A implementação de futuros
Este tópico mostra como implementar futuros em seu aplicativo. O tópico demonstra como combinar a funcionalidade existente no Runtime de simultaneidade em algo que faz mais.
A tarefa é um cálculo que pode ser decomposto em cálculos adicionais, mais refinados,. A futuros é uma tarefa assíncrona que calcula um valor para uso posterior.
Para implementar o futures, este tópico define o async_future classe. O async_future classe usa esses componentes do Runtime de simultaneidade: o Concurrency::task_group classe e o Concurrency::single_assignment classe. O async_future classe usa a task_group classe para calcular um valor de forma assíncrona e a single_assignment classe para armazenar o resultado do cálculo. O construtor da async_future classe usa uma função de trabalho que calcula o resultado e o get método recupera o resultado.
Para implementar a classe futura
Declara uma classe de modelo chamada async_future que é parametrizado no tipo de cálculo resultante. Adicionar public e private seções para esta classe.
template <typename T> class async_future { public: private: };
No private seção a async_future da classe, declare uma task_group e um single_assignment membro de dados.
// Executes the asynchronous work function. task_group _tasks; // Stores the result of the asynchronous work function. single_assignment<T> _value;
No public seção a async_future classe, implemente o construtor. O construtor é um modelo que é parametrizado sobre a função de trabalho que calcula o resultado. O construtor assincronamente executa a função de trabalho na task_group membro de dados e usa o Concurrency::send função para gravar o resultado para o single_assignment membro de dados.
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()); }); }
No public seção a async_future classe, implemente o destruidor. O destruidor aguarda que a tarefa seja concluída.
~async_future() { // Wait for the task to finish. _tasks.wait(); }
No public seção a async_future da classe, implementar a get método. Esse método usa o Concurrency::receive função para recuperar o resultado da função de trabalho.
// 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); }
Exemplo
Descrição
O exemplo a seguir mostra o completo async_future classe e um exemplo de uso. O wmain função cria uma std:: Vector o objeto que contém valores de 10.000 inteiro aleatório. Depois ele usa async_future objetos para localizar os valores menores e maiores que estão contidos no vector objeto.
Có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(values.begin(), values.end(), [&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(values.begin(), values.end(), [&](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(values.begin(), values.end(), [&](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(values.begin(), values.end(), 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;
}
Comentários
Esse exemplo produz a seguinte saída.
smallest: 0
largest: 9999
average: 4981
O exemplo usa o async_future::get método para recuperar os resultados do cálculo. O async_future::get método aguarda que a computação concluir se a computação é ainda ativo.
Programação robusta
Para estender o async_future classe para manipular exceções lançadas pela função de trabalho, modificar o async_future::get método para chamar o Concurrency::task_group::wait método. O task_group::wait método lança exceções que foram geradas pela função de trabalho.
O exemplo a seguir mostra a versão modificada da async_future classe. O wmain função usa um try–catch bloco para imprimir o resultado do async_future objeto ou para imprimir o valor da exceção que é gerado pela função de trabalho.
// 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;
}
}
Esse exemplo produz a seguinte saída.
caught exception: error
Para obter mais informações sobre o modelo de tratamento de exceção no Runtime de simultaneidade, consulte O Runtime de simultaneidade de manipulação de exceção.
Compilando o código
Copie o código de exemplo e colá-lo em um Visual Studio do projeto, ou colá-lo em um arquivo que é chamado futures.cpp e, em seguida, execute o seguinte comando um Visual Studio 2010 janela do Prompt de comando.
cl.exe /EHsc futures.cpp
Consulte também
Referência
Conceitos
O Runtime de simultaneidade de manipulação de exceção