Cara: Menggunakan Penanganan Pengecualian untuk Memutuskan dari Perulangan Paralel

Topik ini menunjukkan cara menulis algoritma pencarian untuk struktur pohon dasar.

Topik Pembatalan menjelaskan peran pembatalan di Pustaka Pola Paralel. Penggunaan penanganan pengecualian adalah cara yang kurang efisien untuk membatalkan pekerjaan paralel daripada penggunaan metode konkurensi::task_group::cancel dan konkurensi::structured_task_group::batal . Namun, satu skenario di mana penggunaan penanganan pengecualian untuk membatalkan pekerjaan sesuai adalah ketika Anda memanggil ke pustaka pihak ketiga yang menggunakan tugas atau algoritma paralel tetapi tidak menyediakan task_group objek atau structured_task_group untuk dibatalkan.

Contoh: Jenis pohon dasar

Contoh berikut menunjukkan jenis dasar tree yang berisi elemen data dan daftar simpul anak. Bagian berikut menunjukkan isi for_all metode , yang secara rekursif melakukan fungsi kerja pada setiap simpul anak.

// A simple tree structure that has multiple child nodes.
template <typename T>
class tree
{
public:
   explicit tree(T data)
      : _data(data)
   {
   }

   // Retrieves the data element for the node. 
   T get_data() const
   {
      return _data;
   }

   // Adds a child node to the tree.
   void add_child(tree& child)
   {
      _children.push_back(child);
   }

   // Performs the given work function on the data element of the tree and
   // on each child.
   template<class Function>
   void for_all(Function& action);

private:
   // The data for this node.
   T _data;
   // The child nodes.
   list<tree> _children;
};

Contoh: Melakukan pekerjaan secara paralel

Contoh berikut menunjukkan for_all metode . Ini menggunakan algoritma konkurensi::p arallel_for_each untuk melakukan fungsi kerja pada setiap simpul pohon secara paralel.

// Performs the given work function on the data element of the tree and
// on each child.
template<class Function>
void for_all(Function& action)
{
   // Perform the action on each child.
   parallel_for_each(begin(_children), end(_children), [&](tree& child) {
      child.for_all(action);
   });

   // Perform the action on this node.
   action(*this);
}

Contoh: Mencari pohon untuk nilai

Contoh berikut menunjukkan search_for_value fungsi, yang mencari nilai dalam objek yang disediakan tree . Fungsi ini diteruskan ke for_all metode fungsi kerja yang melempar ketika menemukan simpul pohon yang berisi nilai yang disediakan.

Asumsikan bahwa tree kelas disediakan oleh pustaka pihak ketiga, dan Anda tidak dapat memodifikasinya. Dalam hal ini, penggunaan penanganan pengecualian sesuai karena for_all metode tidak menyediakan task_group atau structured_task_group objek kepada pemanggil. Oleh karena itu, fungsi kerja tidak dapat langsung membatalkan grup tugas induknya.

Saat fungsi kerja yang Anda berikan ke grup tugas memberikan pengecualian, runtime menghentikan semua tugas yang ada di grup tugas (termasuk grup tugas turunan apa pun) dan membuang tugas apa pun yang belum dimulai. Fungsi ini search_for_value menggunakan try-catch blok untuk menangkap pengecualian dan mencetak hasilnya ke konsol.

// Searches for a value in the provided tree object.
template <typename T>
void search_for_value(tree<T>& t, int value)
{
   try
   {
      // Call the for_all method to search for a value. The work function
      // throws an exception when it finds the value.
      t.for_all([value](const tree<T>& node) {
         if (node.get_data() == value)
         {
            throw &node;
         }
      });
   }
   catch (const tree<T>* node)
   {
      // A matching node was found. Print a message to the console.
      wstringstream ss;
      ss << L"Found a node with value " << value << L'.' << endl;
      wcout << ss.str();
      return;
   }

   // A matching node was not found. Print a message to the console.
   wstringstream ss;
   ss << L"Did not find node with value " << value << L'.' << endl;
   wcout << ss.str();   
}

Contoh: Membuat dan mencari pohon secara paralel

Contoh berikut membuat tree objek dan mencarinya untuk beberapa nilai secara paralel. Fungsi build_tree ini ditampilkan nanti dalam topik ini.

int wmain()
{  
   // Build a tree that is four levels deep with the initial level 
   // having three children. The value of each node is a random number.
   mt19937 gen(38);
   tree<int> t = build_tree<int>(4, 3, [&gen]{ return gen()%100000; });

   // Search for a few values in the tree in parallel.
   parallel_invoke(
      [&t] { search_for_value(t, 86131); },
      [&t] { search_for_value(t, 17522); },
      [&t] { search_for_value(t, 32614); }
   );
}

Contoh ini menggunakan algoritma concurrency::p arallel_invoke untuk mencari nilai secara paralel. Untuk informasi selengkapnya tentang algoritma ini, lihat Algoritma Paralel.

Contoh: Sampel kode penanganan pengecualian selesai

Contoh lengkap berikut menggunakan penanganan pengecualian untuk mencari nilai dalam struktur pohon dasar.

// task-tree-search.cpp
// compile with: /EHsc
#include <ppl.h>
#include <list>
#include <iostream>
#include <algorithm>
#include <sstream>
#include <random>

using namespace concurrency;
using namespace std;

// A simple tree structure that has multiple child nodes.
template <typename T>
class tree
{
public:
   explicit tree(T data)
      : _data(data)
   {
   }

   // Retrieves the data element for the node. 
   T get_data() const
   {
      return _data;
   }

   // Adds a child node to the tree.
   void add_child(tree& child)
   {
      _children.push_back(child);
   }

   // Performs the given work function on the data element of the tree and
   // on each child.
   template<class Function>
   void for_all(Function& action)
   {
      // Perform the action on each child.
      parallel_for_each(begin(_children), end(_children), [&](tree& child) {
         child.for_all(action);
      });

      // Perform the action on this node.
      action(*this);
   }

private:
   // The data for this node.
   T _data;
   // The child nodes.
   list<tree> _children;
};

// Builds a tree with the given depth. 
// Each node of the tree is initialized with the provided generator function.
// Each level of the tree has one more child than the previous level.
template <typename T, class Generator>
tree<T> build_tree(int depth, int child_count, Generator& g)
{
   // Create the tree node.
   tree<T> t(g());

   // Add children.
   if (depth > 0)
   {
      for(int i = 0; i < child_count; ++i)
      {
         t.add_child(build_tree<T>(depth - 1, child_count + 1, g));
      }
   }

   return t;
}

// Searches for a value in the provided tree object.
template <typename T>
void search_for_value(tree<T>& t, int value)
{
   try
   {
      // Call the for_all method to search for a value. The work function
      // throws an exception when it finds the value.
      t.for_all([value](const tree<T>& node) {
         if (node.get_data() == value)
         {
            throw &node;
         }
      });
   }
   catch (const tree<T>* node)
   {
      // A matching node was found. Print a message to the console.
      wstringstream ss;
      ss << L"Found a node with value " << value << L'.' << endl;
      wcout << ss.str();
      return;
   }

   // A matching node was not found. Print a message to the console.
   wstringstream ss;
   ss << L"Did not find node with value " << value << L'.' << endl;
   wcout << ss.str();   
}

int wmain()
{  
   // Build a tree that is four levels deep with the initial level 
   // having three children. The value of each node is a random number.
   mt19937 gen(38);
   tree<int> t = build_tree<int>(4, 3, [&gen]{ return gen()%100000; });

   // Search for a few values in the tree in parallel.
   parallel_invoke(
      [&t] { search_for_value(t, 86131); },
      [&t] { search_for_value(t, 17522); },
      [&t] { search_for_value(t, 32614); }
   );
}

Contoh ini menghasilkan output sampel berikut.

Found a node with value 32614.
Found a node with value 86131.
Did not find node with value 17522.

Mengompilasi Kode

Salin kode contoh dan tempelkan dalam proyek Visual Studio, atau tempelkan dalam file yang diberi nama task-tree-search.cpp lalu jalankan perintah berikut di jendela Prompt Perintah Visual Studio.

cl.exe /EHsc task-tree-search.cpp

Baca juga

Pembatalan di PPL
Penanganan Pengecualian
Paralelisme Tugas
Algoritma Paralel
Kelas task_group
Kelas structured_task_group
Fungsi parallel_for_each