Procedura: eseguire operazioni di mapping e riduzione in parallelo
In questo esempio viene illustrato come utilizzare il concurrency::parallel_transform e concurrency::parallel_reduce gli algoritmi e le concurrency::concurrent_unordered_map classe per contare le occorrenze delle parole nei file.
A mappa operazione si applica una funzione per ogni valore di una sequenza.A ridurre operazione combina gli elementi di una sequenza in un unico valore.È possibile utilizzare il modello di libreria STL (Standard) std::transformstd::accumulate classi per eseguire il mapping e ridurre le operazioni.Tuttavia, per migliorare le prestazioni per molti problemi, è possibile utilizzare la parallel_transform algoritmo per eseguire l'operazione di mappa in parallelo e la parallel_reduce algoritmo per eseguire l'operazione di riduzione in parallelo.In alcuni casi, è possibile utilizzare concurrent_unordered_map per eseguire il mapping e la riduzione in un'unica operazione.
Esempio
Nell'esempio seguente viene contato le occorrenze delle parole nei file.Utilizza std:: Vector per rappresentare il contenuto di due file.L'operazione di mapping consente di calcolare le occorrenze di ogni parola in ciascun vettore.L'operazione di riduzione si accumula il conteggio delle parole in entrambi i vettori.
// 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.
*/
Compilazione del codice
Per compilare il codice, copiarlo e incollarlo in un progetto di Visual Studio o incollarlo in un file denominato parallelo-mappa-reduce.cpp e quindi eseguire il comando riportato di seguito in una finestra del prompt dei comandi di Visual Studio.
cl.exe /EHsc parallel-map-reduce.cpp
Programmazione efficiente
In questo esempio, è possibile utilizzare la concurrent_unordered_map classe, ovvero che è definito in concurrent_unordered_map.h—to di eseguire il mapping e ridurre in un'unica operazione.
// 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.
*/
In genere, parallelizzare solo con l'esterno o il ciclo interno.Se si dispone di un numero relativamente limitato di file e ciascun file contiene molte parole, parallelizzare il ciclo interno.Parallelizzare il ciclo esterno se si dispone relativamente molti file e ciascun file contiene alcune parole.
Vedere anche
Riferimenti
Classe concurrent_unordered_map