Anteckning
Åtkomst till den här sidan kräver auktorisering. Du kan prova att logga in eller ändra kataloger.
Åtkomst till den här sidan kräver auktorisering. Du kan prova att ändra kataloger.
Det här avsnittet visar hur du implementerar futures i din applikation. Avsnittet visar hur du kombinerar befintliga funktioner i Concurrency Runtime till något som gör mer.
Viktigt!
Det här avsnittet illustrerar begreppet terminer för demonstrationsändamål. Vi rekommenderar att du använder std::future eller concurrency::task när du behöver en asynkron uppgift som beräknar ett värde för senare användning.
En uppgift är en beräkning som kan delas upp i ytterligare, mer detaljerade beräkningar. En framtid är en asynkron uppgift som beräknar ett värde för senare användning.
För att implementera futures-kontrakt definieras klassen i det här avsnittet. Klassen async_future använder dessa komponenter i concurrency Runtime: klassen concurrency::task_group och klassen concurrency::single_assignment . Klassen async_future använder task_group klassen för att beräkna ett värde asynkront och single_assignment klassen för att lagra resultatet av beräkningen. Konstruktorn för async_future klassen tar en arbetsfunktion som beräknar resultatet och get metoden hämtar resultatet.
Implementera klassen async_future
- Deklarera en mallklass med namnet
async_futuresom parameteriseras på typen av den resulterande beräkningen. Lägg tillpublicochprivateavsnitt i den här klassen.
template <typename T>
class async_future
{
public:
private:
};
- I avsnittet
privateiasync_futureklassen deklarerar du entask_groupoch ensingle_assignmentdatamedlem.
// Executes the asynchronous work function.
task_group _tasks;
// Stores the result of the asynchronous work function.
single_assignment<T> _value;
- I avsnittet
publiciasync_futureklassen implementerar du konstruktorn. Konstruktorn är en mall som parametriseras på den arbetsfunktion som beräknar resultatet. Konstruktorn kör asynkront arbetsfunktionen itask_groupdatamedlemmen och använder funktionen concurrency::send för att skriva resultatet tillsingle_assignmentdatamedlemmen.
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());
});
}
- I avsnittet
publiciasync_futureklassen implementerar du destructor. Destructor väntar på att uppgiften ska slutföras.
~async_future()
{
// Wait for the task to finish.
_tasks.wait();
}
- I avsnittet
publiciasync_futureklassen implementerar dugetmetoden. Den här metoden använder funktionen concurrency::receive för att hämta resultatet av arbetsfunktionen.
// 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);
}
Exempel
Beskrivning
I följande exempel visas hela async_future klassen och ett exempel på dess användning. Funktionen wmain skapar ett std::vector-objekt som innehåller 10 000 slumpmässiga heltalsvärden. Den använder async_future sedan objekt för att hitta de minsta och största värdena som finns i vector objektet.
Kod
// 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;
}
Kommentarer
Det här exemplet genererar följande utdata:
smallest: 0
largest: 9999
average: 4981
I exemplet används async_future::get metoden för att hämta resultatet av beräkningen. Metoden async_future::get väntar på att beräkningen ska slutföras om beräkningen fortfarande är aktiv.
Robust Programmering
Om du vill utöka async_future klassen för att hantera undantag som genereras av arbetsfunktionen ändrar du async_future::get metoden så att den anropar metoden concurrency::task_group::wait . Metoden task_group::wait kastar alla undantag som genererades av arbetsfunktionen.
I följande exempel visas den ändrade versionen av async_future klassen. Funktionen wmain använder ett try-catch block för att skriva ut resultatet av async_future-objektet eller för att skriva ut värdet för undantaget som genereras av den operativa funktionen.
// 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;
}
}
Det här exemplet genererar följande utdata:
caught exception: error
Mer information om undantagshanteringsmodellen i Concurrency Runtime finns i Undantagshantering.
Kompilera koden
Kopiera exempelkoden och klistra in den i ett Visual Studio-projekt, eller klistra in den i en fil med namnet futures.cpp och kör sedan följande kommando i ett Visual Studio-kommandotolkfönster.
cl.exe /EHsc futures.cpp
Se även
Genomgång av samtidighetskörning
undantagshantering
task_group-klass
SingleAssignment-klass