方法: マップ操作と縮小操作を並列実行する
この例で concurrency::parallel_transform と concurrency::parallel_reduce アルゴリズムとファイルの単語の発生をカウントに concurrency::concurrent_unordered_map クラスを使用する方法を示します。
マップ 操作では、シーケンスの各値に関数を適用します。 単純化する 操作は、値 1 は、シーケンスの要素を結合します。 マップを実行し、操作を単純化するのテンプレート ライブラリ (STL) 標準 std::transformstd::accumulate クラスを使用できます。 ただし、多くの問題のパフォーマンスを向上させるために、マップ操作と単純化する操作を並列に実行する parallel_reduce アルゴリズムを並列実行するために、parallel_transform アルゴリズムを使用できます。 場合によっては、単純化する 1 回の操作でマップと実行に concurrent_unordered_map を使用できます。
使用例
次の例では、ファイルの単語の発生をカウント。 これは、2 種類のファイルの内容を表すために 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.h-to で実行し、マップを 1 回の操作で単純化する定義された concurrent_unordered_map を使用できます。
// 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.
*/
通常、内側または外側のループを並列化します。 比較的少数のファイルがあり、各ファイルが複数の単語を含む場合は内側のループを並列化します。 多くのファイルが比較的、各ファイルがいくつかのテキストが含まれている場合は、外側のループを並列化します。