如何:平行執行對應和縮減作業
此範例示範如何使用 concurrency::p arallel_transform 和 concurrency::p arallel_reduce 演算法和 concurrency::concurrent_unordered_map 類別來計算檔案中字數的出現次數。
對應作業會將函式套用至序列中的每個值。 歸納作業會將序列的項目結合成一個值。 您可以使用C++標準連結庫 std::transform 和 std::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 {
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.
*/
編譯程式碼
若要編譯程式代碼,請複製程式代碼,然後將它貼到Visual Studio專案中,或貼到名為 parallel-map-reduce.cpp
的檔案中,然後在Visual Studio 命令提示字元視窗中執行下列命令。
cl.exe /EHsc parallel-map-reduce.cpp
穩固程式設計
在這個範例中,您可以使用在 concurrent_unordered_map.h中定義的 concurrent_unordered_map
類別,在一個作業中執行對應和縮減。
// 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.
*/
一般而言,您只會平行處理外部或內部迴圈。 如果您的檔案數相當少,而且每個檔案包含許多單字,則請平行處理內部迴圈。 如果您的檔案數相當多,而且每個檔案包含少數單字,則請平行處理外部迴圈。
另請參閱
平行演算法
parallel_transform函式
parallel_reduce函式
concurrent_unordered_map 類別