3

コードのある時点で、unordered_map 内のすべての要素に対して操作を行う必要があります。このプロセスを高速化するために、openMP を使用したいのですが、単純なアプローチではうまくいきません。

std::unordered_map<size_t, double> hastTable;

#pragma omp for
for(auto it = hastTable.begin();
    it != hastTable.end();
    it ++){
//do something
}

これは、unordered_map の反復子がランダム アクセス反復子ではないためです。別の方法として、for_each で動作する __gnu_parallel ディレクティブを試しました。しかし、次のコード

#include <parallel/algorithm>
#include <omp.h>

__gnu_parallel::for_each (hashTable.begin(), hashTable.end(),[](std::pair<const size_t, double> & item)
                        {
                          //do something with item.secon
                        });

(gcc 4.8.2) でコンパイル

 g++ -fopenmp -march=native -std=c++11

並行して走らない。ベクトルで unordered_map を切り替え、同じ __gnu_parallel ディレクティブを使用すると、並列で実行されます。

順序付けられていないマップの場合、なぜ並列に実行されないのですか? 回避策はありますか?

以下に、私の問題を再現する簡単なコードをいくつか示します。

#include <unordered_map>
#include <parallel/algorithm>
#include <omp.h>

int main(){

//unordered_map                                                                                                                                      
std::unordered_map<size_t, double> hashTable;
double val = 1.;
for(size_t i = 0; i<100000000; i++){
  hashTable.emplace(i, val);
  val += 1.;
}
__gnu_parallel::for_each (hashTable.begin(), hashTable.end(),[](std::pair<const size_t, double> & item)
                        {
                          item.second *= 2.;
                        });

//vector                                                                                                                                             
std::vector<double> simpleVector;
val = 1.;
for(size_t i = 0; i<100000000; i++){
  simpleVector.push_back(val);
  val += 1.;
}
__gnu_parallel::for_each (simpleVector.begin(), simpleVector.end(),[](double & item)
                        {
                          item *= 2.;
                        });

}

あなたの答えを楽しみにしています。

4

3 に答える 3

7

ランダム イテレーターをサポートしないコンテナーでの標準的なアプローチは、明示的な OpenMP タスクを使用することです。

std::unordered_map<size_t, double> hastTable;

#pragma omp parallel
{
   #pragma omp single
   {
      for(auto it = hastTable.begin(); it != hastTable.end(); it++) {
         #pragma omp task
         {
            //do something
         }
      }
   }
}

これにより、反復ごとに個別のタスクが作成され、オーバーヘッドが発生するため、//do something実際に意味がある場合にのみ意味があります//do quite a bit of work

于 2014-09-25T12:07:45.217 に答える