2012-03-31 5 views
6

私は使用しているプログラムをparallizeしようとしていますが、次の質問があります。 複数のスレッドが同じベクトルでもベクトルの異なる要素を読み書きする必要がある場合、パフォーマンスが低下しますか?私の気持ちは、私のプログラムがそれを視覚化することでほとんど遅くならないという理由があります。次のコードを取る:OpenMPの共有ベクター

#include <vector> 

int main(){ 

    vector<double> numbers; 
    vector<double> results(10); 
    double x; 

    //write 10 values in vector numbers 
    for (int i =0; i<10; i++){ 
     numbers.push_back(cos(i)); 
    } 

#pragma omp parallel for \ 
    private(x) \ 
    shared(numbers, results) 
     for(int j = 0; j < 10; j++){ 

      x = 2 * numbers[j] + 5; 
#pragma omp critical // do I need this ? 
      { 
       results[j] = x;  
      } 
     } 

    return 0; 

} 

明らかに実際のプログラムでは、はるかに高価な操作を行いますが、この例では唯一の私の質問を説明し ばなりません。それで、forループは高速かつ完全に並列処理できますか、あるいは、異なるスレッドはお互いに待ち合わせる必要がありますか?ベクトルの異なる要素をすべて読み込んでいますが、一度に1つのスレッドしかベクトル番号にアクセスできないためです。

書き込み操作で同じ質問:すべてのスレッドがベクトル結果の異なる要素に書き込むため、クリティカルなプラグマが必要ですか、問題ありませんか? 私は得ることができるあらゆる援助に満足していますし、これを行う良い方法があるかどうかを知ることも良いでしょう(ベクトルをまったく使用しないかもしれませんが、単純な配列やポインタなど?) 私はベクトルaren場合によってはスレッドセーフで、ポインタを使用することをお勧めします:OpenMP and STL vector

ありがとうございました!

答えて

7

複数のスレッド内のベクトルの問題の大部分は、サイズ変更が必要な場合、ベクターの内容全体をメモリ内の新しい場所(より大きな割り当てられたチャンク)にコピーすると思いますこれに並列にアクセスすると、削除されたオブジェクトを読み込もうとしました。不足については

あなたは、配列のサイズを変更していない場合は、私が同時読み取りとのトラブルがあったことがなかったしているベクターに書き込む(明らかに限り、私は二度同じ要素を書いていないよと)

(実際にそのクリティカルセクションの外で行われる量に応じて)

クリティカルセクションステートメントを削除することができます上記を念頭に置いて)。

+0

彼はまったくベクトルのサイズを変更しません。 – eudoxos

+0

@eudoxos私は、コードスニペットから、特定の条件の下でSTLベクトルがスレッドセーフではないという事実を提起して以来、それが言及されたことを確かめたいと思っていました。 – SirGuy

+0

+1:ここでは、appending、resizingなどのベクトル固有の操作はスレッドセーフではなく、おそらく破損することに注意してください。しかし、各要素が1つのスレッドだけによって書き込まれている限り、ベクトルの要素に対して操作するだけで問題ありません。 –

5

同じ要素が同時に変更されることはないため、重要なセクティノのためにスピードアップする必要はありません。クリティカルセクションの部分を削除しても問題ありません。

メモリアクセスが線形でない場合(これは例のとおりです)、スレッドはキャッシュ(同じキャッシュラインの要素を書き込む)と戦う可能性があるため、スケジュール戦略でもプレイできます。あなたの場合のように要素の数が与えられてループに分岐がない場合(したがって、それらはほぼ同じ速度で実行されます)、デフォルトのIIRCであるstaticが最適です。

(ところで、あなたがprivate(x)を避けるために、ループ内xを宣言することができますし、sharedディレクティブがIIRC(私はそれを使用したことがない)暗黙的に指定されます。)

+0

+1;サイズを変更したり追加したりしていない場合やベクターを持っている場合は、1次元の配列であり、OpenMPは配列を操作する上で非常に優れています。静的、私的などについては、 "ベストプラクティス"は、デフォルト(none)を使用し、明示的にすべてを明示的にプライベートまたは共有にすること、そして@ eudoxosが指摘するように、パラレルセクションを暗黙的に非公開にして、コードに従うのが少し簡単です。 –

+0

ご協力いただきありがとうございます。上のようにループの前ではなく、ループ内でxを宣言することは本当に高速です(すべてのスレッドはそれを宣言します)。これは同じパフォーマンスの賢明ですが、見栄えが良いですか?メモリアクセスが線形ではなく、なぜそうであるのはどういう意味ですか? – user1304680

+0

@ user1304680:宣言はコンパイラのためのものです。ちょうどあなたがいくつかのサイズのメモリを持っていて、それを後のコードで何とかしたいと言っているだけです。まともな、適度に最適化されたコンパイラには違いがあるとは思わない。非線形アクセス:隣接メモリ領域のスレッドから要素へのランダムアクセスを意味しました。 RAMはCPUへのメモリのチャンクを提供し、これはベクトルアイテムより大きい。 2つのコアが近くにあるRAMにアクセスすると、同じキャッシュラインにある可能性があり、それらはhwレベルで同期されますが、速度が遅くなります。あなたが必要になるまでそれについて心配しないでください。 – eudoxos

関連する問題