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
- Deklarujte třídu šablony s názvem
async_future
, která je parametrizována pro typ výsledného výpočtu. Přidejtepublic
doprivate
této třídy oddíly.
template <typename T>
class async_future
{
public:
private:
};
private
V částiasync_future
třídy deklarujtetask_group
asingle_assignment
datový člen.
// Executes the asynchronous work function.
task_group _tasks;
// Stores the result of the asynchronous work function.
single_assignment<T> _value;
public
V částiasync_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 členutask_group
a použije funkci concurrency::send k zápisu výsledku do datového členusingle_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());
});
}
public
V částiasync_future
třídy implementujte destruktor. Destruktor čeká na dokončení úkolu.
~async_future()
{
// Wait for the task to finish.
_tasks.wait();
}
public
V částiasync_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ácatch
try
-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