Panduan: Menerapkan Futures
Topik ini menunjukkan cara menerapkan futures di aplikasi Anda. Topik ini menunjukkan cara menggabungkan fungsionalitas yang ada dalam Runtime Konkurensi menjadi sesuatu yang melakukan lebih banyak hal.
Penting
Topik ini menggambarkan konsep futures untuk tujuan demonstrasi. Kami menyarankan agar Anda menggunakan std::future atau concurrency::task saat Anda memerlukan tugas asinkron yang menghitung nilai untuk digunakan nanti.
Tugas adalah komputasi yang dapat diurai menjadi komputasi tambahan yang lebih halus. Masa depan adalah tugas asinkron yang menghitung nilai untuk digunakan nanti.
Untuk menerapkan futures, topik ini mendefinisikan async_future
kelas . Kelas async_future
ini menggunakan komponen Runtime Konkurensi ini: kelas konkurensi::task_group dan kelas konkurensi::single_assignment . Kelas async_future
menggunakan task_group
kelas untuk menghitung nilai secara asinkron dan single_assignment
kelas untuk menyimpan hasil komputasi. Konstruktor async_future
kelas mengambil fungsi kerja yang menghitung hasilnya, dan get
metode mengambil hasilnya.
Untuk menerapkan kelas async_future
- Deklarasikan kelas templat bernama
async_future
yang diparameterkan pada jenis komputasi yang dihasilkan. Tambahkanpublic
bagian danprivate
ke kelas ini.
template <typename T>
class async_future
{
public:
private:
};
- Di bagian
private
async_future
kelas, deklarasikantask_group
dansingle_assignment
anggota data.
// Executes the asynchronous work function.
task_group _tasks;
// Stores the result of the asynchronous work function.
single_assignment<T> _value;
- Di bagian
public
async_future
kelas, terapkan konstruktor. Konstruktor adalah templat yang diparameterkan pada fungsi kerja yang menghitung hasilnya. Konstruktor secara asinkron menjalankan fungsi kerja ditask_group
anggota data dan menggunakan fungsi konkurensi::kirim untuk menulis hasilnya kepadasingle_assignment
anggota data.
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());
});
}
- Di bagian
public
async_future
kelas, terapkan destruktor. Destruktor menunggu tugas selesai.
~async_future()
{
// Wait for the task to finish.
_tasks.wait();
}
- Di bagian
public
async_future
kelas, terapkanget
metode . Metode ini menggunakan fungsi konkurensi::receive untuk mengambil hasil fungsi kerja.
// 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);
}
Contoh
Deskripsi
Contoh berikut menunjukkan kelas lengkap async_future
dan contoh penggunaannya. Fungsi ini wmain
membuat objek std::vector yang berisi 10.000 nilai bilangan bulat acak. Kemudian menggunakan async_future
objek untuk menemukan nilai terkecil dan terbesar yang terkandung dalam vector
objek.
Kode
// 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;
}
Komentar
Contoh ini menghasilkan output berikut:
smallest: 0
largest: 9999
average: 4981
Contoh menggunakan async_future::get
metode untuk mengambil hasil komputasi. Metode async_future::get
menunggu komputasi selesai jika komputasi masih aktif.
Pemrograman yang Kuat
Untuk memperluas async_future
kelas untuk menangani pengecualian yang dilemparkan oleh fungsi kerja, ubah async_future::get
metode untuk memanggil metode konkurensi::task_group::tunggu . Metode ini task_group::wait
melemparkan pengecualian apa pun yang dihasilkan oleh fungsi kerja.
Contoh berikut menunjukkan versi kelas yang dimodifikasi async_future
. Fungsi ini wmain
menggunakancatch
try
-blok untuk mencetak hasil async_future
objek atau untuk mencetak nilai pengecualian yang dihasilkan oleh fungsi kerja.
// 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;
}
}
Contoh ini menghasilkan output berikut:
caught exception: error
Untuk informasi selengkapnya tentang model penanganan pengecualian di Runtime Konkurensi, lihat Penanganan Pengecualian.
Mengompilasi Kode
Salin kode contoh dan tempelkan dalam proyek Visual Studio, atau tempelkan dalam file yang diberi nama futures.cpp
lalu jalankan perintah berikut di jendela Prompt Perintah Visual Studio.
cl.exe /EHsc futures.cpp
Lihat juga
Panduan Runtime Konkurensi
Penanganan Pengecualian
Kelas task_group
Kelas single_assignment