2012-01-24 28 views
4

piを計算するために私のモンテカルロ法を並列化するのに問題があります。ここではforループ並列化されていますpi計算のOpenMP並列化が遅いか間違っている

#pragma omp parallel for private(i,x,y) schedule(static) reduction(+:count) 
    for (i = 0; i < points; i++) { 
    x = rand()/(RAND_MAX+1.0)*2 - 1.0; 
    y = rand()/(RAND_MAX+1.0)*2 - 1.0; 

    // Check if point lies in circle 
    if(x*x + y*y < 1.0) { count++; } 
    } 

問題は、私はschedule(dynamic)を使用している場合、それは私がschedule(static)を使用する場合は、パイを過小評価し、シリアル実装よりもその遅く、です。私は間違って何をしていますか?私はそれを修正する他の方法を試しました(このように:Using OpenMP to calculate the value of PI)が、シリアル実装よりもずっと遅いです。あなたがCライブラリrand機能を使用していると仮定すると、事前に

おかげ

+0

'rand()'はスレッドセーフですか? – Mysticial

+0

@Mystical:これはそうではないようです:http://stackoverflow.com/questions/6161322/using-rand-with-multiple-threads-in-c –

+0

私は@Mysticialが正しいアイデアを持っていると思っています。 'rand'は通常、内部的な「シード(seed)」を持ちます。これは、基本的に共有リソースとして機能し、すべての呼び出し時にシリアル化を強制します(そうでない場合は不正確な結果になる)。もし利用可能なら、 'rand_r'または(好ましくは)' drand48_r'を代わりに使ってみてください。あるいは、C++ 11で導入された乱数生成クラスを考えてみましょう。各インスタンスには独自の状態があり、直列化を避ける必要があります(初期化をトリッキーにする可能性があります。 –

答えて

6

は、その関数はリエントラントまたはスレッドセーフではありません。 POSIXはrand_r機能を提供するが、(glibcの文書を引用する):

POSIX.1は、マルチスレッドプログラムで再現 乱数をサポートするために、Cの標準機能を拡張しました。しかし、拡張は深刻な作業のためにひどく設計され、不適切である です。

特に、シードはunsigned intでなければなりません。これは、良いPRNGのために十分なビットがありません。 SVID乱数関数を使用することをお勧めします。そのうちのnrand48_rはおそらくあなたが探しているものです。

また、別のライブラリを使用することもできます。

+0

nrand48_rの使い方は?標準ライブラリには表示されません。シードは短い符号なし整数であるnrand48(&seed)を使うことができます。しかし、スレッドごとに異なるシードを使用すると、パフォーマンスは低下します – Eddy

1

このようなことを並行して行う際に考慮する必要があることの1つは、計算のさまざまな方法によって異なる丸め誤差が発生する可能性があることです。

例:(A+B)(C+D)が並列に計算される

((A+B) + (C+D))シリアルアプローチ(((A+B) + C) + D)異なる場合があります。

関連する問題