我一直无法使用线程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;
}
答案 0 :(得分:3)
您的代码执行速度有两个原因。
首先,您拥有schedule(dynamic)
子句。这使得循环的调度动态化,即每次迭代按先来先服务的原则安排到单独的线程。这是非常低效的。使用schedule(static)
代替让每个线程执行预先计算的迭代范围。均匀分布是在恒定时间内生成的,因此每次迭代都需要相同的时间,因此无需使用动态调度。
其次,您已指示编译器创建有序并行循环。由于涉及同步,订购会产生非常高的额外开销。在您的情况下,开销甚至更大,因为调度是动态的。
我真的不明白为什么在这种情况下你同时拥有动态时间表和排序。只需将OpenMP pragma替换为:
#pragma omp for schedule(static)
(nowait
条款在这种情况下也只有表面的影响)
答案 1 :(得分:1)
我相信线程正在竞争共享资源,即随机数生成器中state
的共享资源。对于您获取的每个号码,state
都会更新(下次再给出另一个号码)。由于所有随机数只有一个状态,并且需要更新而不受其他线程的干扰,它将强制线程顺序运行(并且因为当你有8个线程调用相同的函数时,锁定会大量争用,从而迫使其他线程等待,这可能意味着调用操作系统花费的时间更多。
另一个因素可能是缓存共享 - state
被所有线程修改,因此每次调用r()
时,保持状态的缓存行都必须无效。
。您可以将distributer(engine)
的来电替换为static int x; return x++;
之类的内容来证明这一点。如果在多进程环境中性能更差(每线程数线性更好),则缓存共享是问题的一部分。