Aracılığıyla paylaş


Nasıl yapılır: Eşleme Gerçekleştirme ve İşlemleri Paralel Olarak Azaltma

Bu örnekte, dosyalardaki sözcüklerin oluşumlarını saymak için concurrency::p arallel_transform and concurrency::p arallel_reduce algoritmalarının ve concurrency::concurrent_unordered_map sınıfının nasıl kullanılacağı gösterilmektedir.

Eşleme işlemi, bir dizideki her değere bir işlev uygular. Azaltma işlemi, bir dizinin öğelerini tek bir değerde birleştirir. Eşleme ve azaltma işlemlerini gerçekleştirmek için C++ Standart Kitaplığı std::transform ve std::accumulate işlevlerini kullanabilirsiniz. Ancak, birçok sorunun performansını artırmak için algoritmayı parallel_transform kullanarak eşleme işlemini paralel ve parallel_reduce azaltma işlemini paralel olarak gerçekleştirmek için algoritmayı kullanabilirsiniz. Bazı durumlarda, haritayı ve azaltmayı tek bir işlemde gerçekleştirmek için kullanabilirsiniz concurrent_unordered_map .

Örnek

Aşağıdaki örnek, dosyalarda sözcüklerin oluşumlarını sayar. İki dosyanın içeriğini temsil etmek için std::vector kullanır. Eşleme işlemi, her bir vektördeki her sözcüğün oluşumlarını hesaplar. Azaltma işlemi, her iki vektörde de sözcük sayılarını biriktirir.

// 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.
*/

Kod Derleniyor

Kodu derlemek için kopyalayın ve visual studio projesine yapıştırın veya adlı parallel-map-reduce.cpp bir dosyaya yapıştırın ve ardından visual studio komut istemi penceresinde aşağıdaki komutu çalıştırın.

cl.exe /EHsc parallel-map-reduce.cpp

Güçlü Programlama

Bu örnekte, eşlemeyi concurrent_unordered_map gerçekleştirmek ve tek bir işlemde azaltmak için concurrent_unordered_map.h dosyasında tanımlanan sınıfını kullanabilirsiniz.

// 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.
*/

Genellikle, yalnızca dış veya iç döngü paralelleştirirsiniz. Görece az sayıda dosyanız varsa ve her dosyada çok sayıda sözcük varsa iç döngüye paralel hale getirebilirsiniz. Nispeten çok sayıda dosyanız varsa ve her dosya birkaç sözcük içeriyorsa dış döngüye paralel hale getirebilirsiniz.

Ayrıca bkz.

Paralel Algoritmalar
parallel_transform İşlevi
parallel_reduce İşlevi
concurrent_unordered_map Sınıfı