Freigeben über


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

parallel_transform-Funktion

parallel_reduce-Funktion

concurrent_unordered_map-Klasse

Konzepte

Parallele Algorithmen