2

スレッド化された C++ 乱数ジェネレーターを単一のコアで標準の rand() よりも優れたものにするのに問題がありました。(複数のスレッドが rand() を呼び出す問題も見られます)

どこかに並行性の問題があることは知っていますが、それを見ることができません。私は以下に到達し、openmp が利用可能な 8 つのコアに分割されていることを知っています。omp 行をコメントアウトすると、より高速な結果が得られます。助けてください!これは私を夢中にさせています!

時代

Single thread
time ./a.out 
real    0m3.497s
user    0m3.492s
sys 0m0.000s

OpemMP 8 cores
g++ -fopenmp randtests.cpp 
time ./a.out 
real    0m14.723s
user    1m52.275s
sys 0m0.712s

コード:

#include <omp.h>        
#include "boost/random.hpp"
#include "boost/generator_iterator.hpp"
#include <iostream>
#include <fstream>
#include <sstream>
#include "boost/random.hpp"

using namespace std;

class RNG
{
public:
    typedef boost::random::mt19937 Engine;
    typedef boost::random::uniform_smallint<int> Distribution;

    Engine engine;
    Distribution distributer;

    RNG() : engine(), distributer() {
        engine.seed();     }

    int operator()() {
        return distributer(engine);
    }
};


int main(void) {

#pragma omp parallel
    {
        int i = omp_get_thread_num();
        unsigned int myseed = i;
        RNG  r;
        int y;
#pragma omp for ordered schedule(dynamic) nowait
        for (unsigned int x = 0; x < 100000000; x++) {
            y = r();
        }
    }

return 0;
}
4

2 に答える 2

1

スレッドが共有リソース、つまりstate乱数ジェネレーターの共有リソースをめぐって競合していることはかなり確信しています。取得した数値ごとにstateが更新されます (次回別の数値を与えるため)。すべての乱数に対して 1 つの状態しかなく、他のスレッドからの干渉なしに更新する必要があるため、スレッドを順次実行する必要があります (同じ関数を呼び出す 8 つのスレッドがあるとロックが激しく競合するため)。 、したがって他のスレッドを強制的に待機させます。おそらく、OS への呼び出しにより多くの時間が費やされることを意味します)。

もう 1 つの要因は、キャッシュ共有である可能性があります。これは、すべてのスレッドによって変更されるため、状態を保持しているキャッシュラインは、呼び出されるstateたびに無効にする必要があります。r()

. distributer(engine)への呼び出しをのようなものに置き換えることで、これを証明できますstatic int x; return x++;。マルチプロセス環境で (スレッド数ごとに直線的に向上するよりも) パフォーマンスが低下する場合は、キャッシュ共有が問題の一部です。

于 2013-04-24T22:14:07.090 に答える