Gewusst wie: Paralleles Ausführen von Zuordnungs- und Reduzierungsoperationen
In diesem Beispiel wird veranschaulicht, wie mithilfe der concurrency::parallel_transform und concurrency::parallel_reduce Algorithmen und die concurrency::concurrent_unordered_map Klasse zählen die Vorkommen von Wörtern in Dateien.
A Anzeigen Vorgang gilt eine Funktion für jeden Wert in einer Sequenz.A reduzieren Operation kombiniert die Elemente einer Sequenz in einem Wert.Sie können die Standard Template Library (STL) std::transformstd::accumulate Klassen zum Ausführen von Zuordnungstests und verringern die.Jedoch zur Verbesserung der Leistung für viele Probleme können Sie die parallel_transform Algorithmus Map-Vorgang Parallel auszuführen und die parallel_reduce Algorithmus Parallel Reduce-Operation auszuführen.In einigen Fällen können Sie concurrent_unordered_map der Karte und die Reduzierung in einem Arbeitsgang ausführen.
Beispiel
Das folgende Beispiel zählt die Vorkommen von Wörtern in Dateien.Es verwendet Std:: Vector um den Inhalt zweier Dateien darstellen.Der Map-Vorgang berechnet die Vorkommen eines Wortes in jeden Vektor.Reduce-Operation sammelt die Anzahl der Wörter in beiden Vektoren.
// parallel-map-reduce.cpp
// compile with: /EHsc
#include <ppl.h>
#include <algorithm>
#include <iostream>
#include <string>
#include <vector>
#include <numeric>
#include <unordered_map>
#include <windows.h>
using namespace concurrency;
using namespace std;
class MapFunc
{
public:
unordered_map<wstring, size_t> operator()(vector<wstring>& elements) const
{
unordered_map<wstring, size_t> m;
for_each(begin(elements), end(elements), [&m](const wstring& elem)
{
m[elem]++;
});
return m;
}
};
struct ReduceFunc : binary_function<unordered_map<wstring, size_t>,
unordered_map<wstring, size_t>, unordered_map<wstring, size_t>>
{
unordered_map<wstring, size_t> operator() (
const unordered_map<wstring, size_t>& x,
const unordered_map<wstring, size_t>& y) const
{
unordered_map<wstring, size_t> ret(x);
for_each(begin(y), end(y), [&ret](const pair<wstring, size_t>& pr) {
auto key = pr.first;
auto val = pr.second;
ret[key] += val;
});
return ret;
}
};
int wmain()
{
// File 1
vector<wstring> v1;
v1.push_back(L"word1"); //1
v1.push_back(L"word1"); //2
v1.push_back(L"word2");
v1.push_back(L"word3");
v1.push_back(L"word4");
// File 2
vector<wstring> v2;
v2.push_back(L"word5");
v2.push_back(L"word6");
v2.push_back(L"word7");
v2.push_back(L"word8");
v2.push_back(L"word1"); //3
vector<vector<wstring>> v;
v.push_back(v1);
v.push_back(v2);
vector<unordered_map<wstring, size_t>> map(v.size());
// The Map operation
parallel_transform(begin(v), end(v), begin(map), MapFunc());
// The Reduce operation
unordered_map<wstring, size_t> result = parallel_reduce(
begin(map), end(map), unordered_map<wstring, size_t>(), ReduceFunc());
wcout << L"\"word1\" occurs " << result.at(L"word1") << L" times. " << endl;
}
/* Output:
"word1" occurs 3 times.
*/
Kompilieren des Codes
Um den Code zu kompilieren, kopieren Sie ihn ein und fügen Sie ihn in einem Projekt Visual Studio oder fügen Sie ihn in eine Datei mit dem Namen Parallel-Karte-reduce.cpp und führen Sie den folgenden Befehl in ein Visual Studio-Eingabeaufforderungsfenster.
cl.exe /EHsc parallel-map-reduce.cpp
Robuste Programmierung
In diesem Beispiel können Sie die concurrent_unordered_map Klasse, die in concurrent_unordered_map.h—to definiert wird, führen Sie die Karte und reduzieren in einem Arbeitsgang.
// File 1
vector<wstring> v1;
v1.push_back(L"word1"); //1
v1.push_back(L"word1"); //2
v1.push_back(L"word2");
v1.push_back(L"word3");
v1.push_back(L"word4");
// File 2
vector<wstring> v2;
v2.push_back(L"word5");
v2.push_back(L"word6");
v2.push_back(L"word7");
v2.push_back(L"word8");
v2.push_back(L"word1"); //3
vector<vector<wstring>> v;
v.push_back(v1);
v.push_back(v2);
concurrent_unordered_map<wstring, size_t> result;
for_each(begin(v), end(v), [&result](const vector<wstring>& words) {
parallel_for_each(begin(words), end(words), [&result](const wstring& word) {
InterlockedIncrement(&result[word]);
});
});
wcout << L"\"word1\" occurs " << result.at(L"word1") << L" times. " << endl;
/* Output:
"word1" occurs 3 times.
*/
Sie zu in der Regel nur das äußere oder innere Schleife parallelisieren.Parallelisieren Sie die innere Schleife, wenn Sie relativ wenige Dateien und jede Datei viele Wörter enthält.Die äußere Schleife zu parallelisieren, wenn Sie relativ viele Dateien und jede Datei einige Wörter enthält.
Siehe auch
Referenz
concurrent_unordered_map-Klasse