HOW TO:平行執行對應和縮減作業
本範例顯示如何使用 concurrency::parallel_transform 和 concurrency::parallel_reduce 演算法和 concurrency::concurrent_unordered_map 類別,以計算出現次數,檔案中的字數。
A 對應作業套用至每個值序列中的函式。A 降低作業結合成一個值序列的項目。您可以使用標準樣板程式庫 (STL) std::transformstd::accumulate 來執行對應,並減少作業的類別。不過,若要改善效能的許多問題,您可以使用parallel_transform以平行方式執行 「 對應 」 作業的演算法和parallel_reduce以平行方式執行縮小作業的演算法。在某些情況下,您可以使用concurrent_unordered_map在單一作業中執行的對應和縮小。
範例
下面範例計算在檔案中的字組的項目。它會使用 std::vector 代表兩個檔案的內容。「 對應 」 作業會計算每個單字的每個向量的出現項目。縮小作業累積兩者都是向量間的字數統計。
// 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.
*/
編譯程式碼
若要編譯的程式碼,將它複製然後將它貼在 Visual Studio 專案中,或將它貼在檔名為 reduce.cpp-對應平行- ,然後執行下列命令,Visual Studio 的命令提示字元] 視窗中。
cl.exe /EHsc parallel-map-reduce.cpp
穩固程式設計
在這個範例中,您可以使用concurrent_unordered_map類別,定義在 concurrent_unordered_map.h—to 會執行對應,並減少在單一作業中。
// 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.
*/
一般而言,您平行處理只有外部或內部迴圈。如果您有很少的檔案,而每個檔案含有許多字詞,平行處理內部迴圈。平行處理外部迴圈,如果您有相當多的檔案,而每個檔案都包含幾個字。