Udostępnij za pośrednictwem


Jak: Użyj obsługi wyjątków do podziału z pętli równoległe

W tym temacie przedstawiono sposób pisania algorytm wyszukiwania dla struktury drzewa podstawowe.

Temat Anulowanie w PPL wyjaśnia roli odwołania w bibliotece desenie równoległych.Korzystanie z obsługi wyjątków jest mniej efektywny sposób, aby anulować równoległą pracę niż w przypadku concurrency::task_group::cancel i concurrency::structured_task_group::cancel metody.Jeden scenariusz, gdzie właściwe jest użycie obsługi wyjątków, aby anulować pracy jest jednak przy wywoływaniu do innej biblioteki, która korzysta z zadań lub algorytmy równoległe, ale nie zapewnia task_group lub structured_task_group obiekt, aby anulować.

Przykład

W poniższym przykładzie przedstawiono podstawowe tree typu, który zawiera element danych, listy węzłów podrzędnych.W poniższej sekcji przedstawiono treści for_all metoda, która rekurencyjnie pełni funkcję pracy na każdy węzeł podrzędny.

// 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;
};

W poniższym przykładzie pokazano for_all metoda.Używa concurrency::parallel_for_each algorytm do pełnienia funkcji pracy w każdym węźle drzewa równolegle.

// 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);
}

W poniższym przykładzie pokazano search_for_value funkcję, która wyszukuje wartość w dołączonym tree obiektu.Funkcja ta przekazuje do for_all metody pracy funkcja, która zgłasza po znalezieniu węzła drzewa, która zawiera podana wartość.

Założenie, że tree klasa pochodzi od innej biblioteki, oraz że nie można go modyfikować.W takim przypadku właściwe jest użycie obsługa wyjątków bo for_all metoda nie dostarcza task_group lub structured_task_group obiektu do obiektu wywołującego.W związku z tym funkcja pracy jest w stanie bezpośrednio anulować jej nadrzędna grupa zadań.

Podczas pracy wyjścia, podawanych przez użytkownika do grupy zadań zgłasza wyjątek, środowiska wykonawczego zatrzymuje wszystkie zadania, które należą do grupy zadań (w tym wszelkich grup zadań podrzędnych) i spowoduje odrzucenie wszystkich zadań, które nie zostały jeszcze rozpoczęte.search_for_value Funkcja używa try-catch bloku na przechwytywanie wyjątku i wydrukuje wyniki do konsoli.

// 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();   
}

Poniższy przykład tworzy tree object i wyszukuje kilka wartości jednocześnie.build_tree Funkcja jest pokazana w dalszej części tego tematu.

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); }
   );
}

W poniższym przykładzie użyto concurrency::parallel_invoke algorytm, aby wyszukać wartości jednocześnie.Aby uzyskać więcej informacji na temat tego algorytmu, zobacz Algorytmy równoległe.

W poniższym przykładzie pełną użyto obsługi wyjątków do wyszukiwania wartości w postaci podstawowych drzewa.

// 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); }
   );
}

Ten przykład generuje następujące przykładowe dane wyjściowe.

  
  
  

Kompilowanie kodu

Skopiuj przykładowy kod i wklej go w projekcie programu Visual Studio lub wklej go w pliku o nazwie zadań drzewa search.cpp a następnie uruchom następujące polecenie w oknie wiersza polecenia usługi programu Visual Studio.

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

Zobacz też

Informacje

Klasa task_group

Klasa structured_task_group

Funkcja parallel_for_each

Koncepcje

Anulowanie w PPL

Obsługa wyjątków w Runtime współbieżności

Zadanie równoległości (współbieżności Runtime)

Algorytmy równoległe