Bagikan melalui


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

  1. Deklarasikan kelas templat bernama async_future yang diparameterkan pada jenis komputasi yang dihasilkan. Tambahkan public bagian dan private ke kelas ini.
template <typename T>
class async_future
{
public:
private:
};
  1. Di bagian private async_future kelas, deklarasikan task_group dan single_assignment anggota data.
// Executes the asynchronous work function.
task_group _tasks;

// Stores the result of the asynchronous work function.
single_assignment<T> _value;
  1. 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 di task_group anggota data dan menggunakan fungsi konkurensi::kirim untuk menulis hasilnya kepada single_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());
    });
}
  1. Di bagian public async_future kelas, terapkan destruktor. Destruktor menunggu tugas selesai.
~async_future()
{
   // Wait for the task to finish.
   _tasks.wait();
}
  1. Di bagian public async_future kelas, terapkan get 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