逐步解說:實作未來
本主題說明如何在應用程式中實作未來。 本主題示範如何將並行運行時間中的現有功能結合成更多功能。
重要
本主題將基於示範目的說明未來的概念。 當您需要計算值以供日後使用的異步工作時,建議您使用 std::future 或 concurrency::task 。
工作是可分解成其他更精細計算的計算。 未來是異步工作,可計算值以供日後使用。
若要實作未來,本主題會定義 類別 async_future
。 類別 async_future
會使用這些並行運行時間的元件: concurrency::task_group 類別和 concurrency::single_assignment 類別。 類別 async_future
會 task_group
使用 類別以異步方式計算值, single_assignment
以及用來儲存計算結果的 類別。 類別的 async_future
建構函式會採用可計算結果的工作函式,而方法會 get
擷取結果。
若要實作 async_future 類別
- 宣告名為
async_future
的範本類別,該類別會在產生的計算類型上參數化。 將和private
區段新增public
至此類別。
template <typename T>
class async_future
{
public:
private:
};
- 在類別的
async_future
區private
段中,宣告task_group
和single_assignment
數據成員。
// Executes the asynchronous work function.
task_group _tasks;
// Stores the result of the asynchronous work function.
single_assignment<T> _value;
- 在 類別的
async_future
區public
段中,實作 建構函式。 建構函式是在計算結果的工作函式上參數化的範本。 建構函式會以異步方式在數據成員中task_group
執行工作函式,並使用 concurrency::send 函式將結果single_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());
});
}
- 在 類別的
async_future
區public
段中,實作解構函式。 解構函式會等候工作完成。
~async_future()
{
// Wait for the task to finish.
_tasks.wait();
}
- 在 類別的
async_future
區public
段中,實get
作 方法。 這個方法會使用 並行::receive 函式來擷取工作函式的結果。
// 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);
}
範例
描述
下列範例顯示完整的 async_future
類別及其使用方式的範例。 函 wmain
式會建立 std::vector 物件,其中包含 10,000 個隨機整數值。 然後,它會使用 async_future
對象來尋找 物件中包含的 vector
最小和最大值。
程式碼
// 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;
}
註解
這個範例會產生下列輸出:
smallest: 0
largest: 9999
average: 4981
此範例會 async_future::get
使用 方法來擷取計算的結果。 如果計算仍在使用中,方法 async_future::get
會等候計算完成。
穩固程式設計
若要擴充 類別 async_future
來處理工作函式擲回的例外狀況,請修改 async_future::get
方法以呼叫 concurrency::task_group::wait 方法。 方法 task_group::wait
會擲回工作函式所產生的任何例外狀況。
下列範例顯示 類別的 async_future
修改版本。 函 wmain
式會使用 try
-catch
區塊來列印物件的結果 async_future
,或列印工作函式所產生的例外狀況值。
// 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;
}
}
這個範例會產生下列輸出:
caught exception: error
如需並行運行時間中例外狀況處理模型的詳細資訊,請參閱 例外狀況處理。
編譯程式碼
複製範例程式代碼,並將其貼到 Visual Studio 專案中,或貼到名為 futures.cpp
的檔案中,然後在 Visual Studio 命令提示字元視窗中執行下列命令。
cl.exe /EHsc futures.cpp