Nasıl yapılır: Paralel Bir Döngüden Kurtulmak için Özel Durum İşlemeyi Kullanma
Bu konu başlığında, temel bir ağaç yapısı için arama algoritması yazma işlemi gösterilmektedir.
İptal konusu Paralel Desenler Kitaplığı'ndaki iptal rolünü açıklar. Özel durum işlemenin kullanımı, paralel çalışmayı iptal etmek için eşzamanlılık::task_group::cancel ve eşzamanlılık::structured_task_group::cancel yöntemlerinin kullanımından daha az verimli bir yöntemdir. Ancak, işi iptal etmek için özel durum işlemenin kullanılmasının uygun olduğu senaryolardan biri, görevleri veya paralel algoritmaları kullanan ancak iptal etmek için bir veya structured_task_group
nesnesi sağlamayan bir task_group
üçüncü taraf kitaplığını çağırmanızdır.
Örnek: Temel ağaç türü
Aşağıdaki örnekte veri öğesi ve alt düğüm listesi içeren temel tree
bir tür gösterilmektedir. Aşağıdaki bölümde, her alt düğümde özyinelemeli olarak bir iş işlevi gerçekleştiren yöntemin gövdesi for_all
gösterilmektedir.
// 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;
};
Örnek: Paralel çalışma gerçekleştirme
Aşağıdaki örnekte yöntemi gösterilmektedir for_all
. Ağacın her düğümünde paralel olarak bir iş işlevi gerçekleştirmek için concurrency::p arallel_for_each algoritmasını kullanır.
// 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);
}
Örnek: Ağaçta değer arama
Aşağıdaki örnekte, sağlanan tree
nesnede search_for_value
bir değer arayan işlevi gösterilmektedir. Bu işlev yöntemine for_all
, sağlanan değeri içeren bir ağaç düğümü bulduğunda oluşturan bir iş işlevi geçirir.
Sınıfın tree
bir üçüncü taraf kitaplığı tarafından sağlandığını ve bunu değiştiremeyeceğinizi varsayalım. Bu durumda, yöntem çağırana bir task_group
veya structured_task_group
nesnesi sağlamadığından özel durum işlemenin kullanımı uygundurfor_all
. Bu nedenle, iş işlevi üst görev grubunu doğrudan iptal edemez.
Bir görev grubuna sağladığınız iş işlevi özel durum oluşturursa, çalışma zamanı görev grubundaki tüm görevleri (alt görev grupları dahil) durdurur ve henüz başlatılmamış görevleri atar. İşlev, search_for_value
özel durumu yakalamak ve sonucu konsola yazdırmak için bir try
-catch
blok kullanır.
// 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();
}
Örnek: Paralel olarak ağaç oluşturma ve arama
Aşağıdaki örnek bir tree
nesne oluşturur ve paralel olarak birkaç değer arar. İşlev build_tree
, bu konunun ilerleyen bölümlerinde gösterilir.
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); }
);
}
Bu örnekte paralel olarak değer aramak için concurrency::p arallel_invoke algoritması kullanılır. Bu algoritma hakkında daha fazla bilgi için bkz . Paralel Algoritmalar.
Örnek: Tamamlanan özel durum işleme kodu örneği
Aşağıdaki tam örnek, temel ağaç yapısındaki değerleri aramak için özel durum işlemeyi kullanır.
// 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); }
);
}
Bu örnek aşağıdaki örnek çıktıyı oluşturur.
Found a node with value 32614.
Found a node with value 86131.
Did not find node with value 17522.
Kod Derleniyor
Örnek kodu kopyalayıp bir Visual Studio projesine yapıştırın veya adlı task-tree-search.cpp
bir dosyaya yapıştırın ve ardından bir Visual Studio Komut İstemi penceresinde aşağıdaki komutu çalıştırın.
cl.exe /EHsc task-tree-search.cpp
Ayrıca bkz.
PPL'de İptal
Özel Durum İşleme
Görev Paralelliği
Paralel Algoritmalar
task_group Sınıfı
structured_task_group Sınıfı
parallel_for_each İşlevi