Gewusst wie: Paralleles Ausführen von Zuordnungs- und Reduzierungsoperationen
In diesem Beispiel wird gezeigt, wie Sie die Parallelität::p arallel_transform and concurrency::p arallel_reduce algorithmen und die Parallelitätsklasse::concurrent_unordered_map verwenden, um die Vorkommen von Wörtern in Dateien zu zählen.
Ein Kartenvorgang wendet eine Funktion auf jeden Wert in einer Sequenz an. Ein Reduzierter Vorgang kombiniert die Elemente einer Sequenz in einem Wert. Sie können die C++-Standardbibliothek std::transform and std::kumulierte Funktionen verwenden, um Zuordnungen durchzuführen und Vorgänge zu reduzieren. Zur Verbesserung der Leistung bei vielen Problemen können Sie mit dem parallel_transform
-Algorithmus parallel den Zuordnungsvorgang und mit dem parallel_reduce
-Algorithmus parallel den Reduzierungsvorgang ausführen. In einigen Fällen können Sie mit concurrent_unordered_map
die Zuordnung und Reduzierung in einem Vorgang durchführen.
Beispiel
Im folgenden Beispiel wird das Vorkommen von Wörtern in Dateien gezählt. Es verwendet std::vector , um den Inhalt von zwei Dateien darzustellen. Der Zuordnungsvorgang berechnet das Vorkommen von jedem Wort in jedem Vektor. Der Reduzierungsvorang zählt die Wörter in den zwei Vektoren zusammen.
// 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 {
L"word1", // 1
L"word1", // 1
L"word2",
L"word3",
L"word4"
};
// File 2
vector<wstring> v2 {
L"word5",
L"word6",
L"word7",
L"word8",
L"word1" // 3
};
vector<vector<wstring>> v { v1, 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, und fügen Sie ihn dann in ein Visual Studio-Projekt ein, oder fügen Sie ihn in eine Datei ein, die benannt parallel-map-reduce.cpp
ist, und führen Sie dann den folgenden Befehl in einem Visual Studio-Eingabeaufforderungsfenster aus.
cl.exe /EHsc parallel-map-reduce.cpp
Stabile Programmierung
In diesem Beispiel können Sie mit der in concurrent_unordered_map.h definierten concurrent_unordered_map
-Klasse die Zuordnung und Reduzierung in einem Vorgang durchführen.
// File 1
vector<wstring> v1 {
L"word1", // 1
L"word1", // 2
L"word2",
L"word3",
L"word4",
};
// File 2
vector<wstring> v2 {
L"word5",
L"word6",
L"word7",
L"word8",
L"word1", // 3
};
vector<vector<wstring>> v { v1, 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.
*/
In der Regel wird nur die äußere oder die innere Schleife parallel ausgeführt. Führen Sie die innere Schleife parallel aus, wenn Sie über relativ wenige Dateien mit vielen Wörtern verfügen. Führen Sie die äußere Schleife parallel aus, wenn Sie über relativ viele Dateien mit wenigen Wörtern verfügen.
Siehe auch
Parallele Algorithmen
parallel_transform-Funktion
parallel_reduce-Funktion
concurrent_unordered_map-Klasse