使用OpenMP分配数组的特殊指令?

时间:2016-04-29 15:29:31

标签: c++ performance openmp

for中用于并行化的简单OpenMP循环是

    vector< double > xs; 
    vector< double > ys; 
    xs.resize(N);
    ys.resize(N);
    if(rank0) printf("Assigning points ...\n");
#pragma omp parallel for
    for(long i = 0; i < N; i++) {
        xs[i] = ((double)rand()/(double)RAND_MAX);
        ys[i] = ((double)rand()/(double)RAND_MAX);
    } 

但是,当我加入#pragma omp parallel for时,这比我不需要的时间要长得多。当我没有使用正确的reduction或类似内容时,通常会看到这种情况,因此我想知道我是否还需要为此#pragma做些什么。

for循环是否还需要#pragma中的其他内容?

请注意,此问题与使用rand()

直接相关

2 个答案:

答案 0 :(得分:3)

我的直接猜测是,问题源于<frame>每次拨打rand()时使用单个种子更新的事实。这意味着即使您正在写入的数组之间没有冲突,每次调用rand()都可能会强制线程之间的同步。

有多种方法可以解决这个问题。一个显而易见的方法是使用C ++ 11中提供的新随机数生成类,每个线程都有一个单独的随机数生成器对象,如下所示:

rand()

至少在对我的系统进行快速测试时,单线程运行大约需要4秒,启用OpenMP大约需要1秒(这是在4核处理器上运行,因此接近完美缩放)。

请注意,如果您使用的是32位系统(或者至少使用生成32位代码的编译器),如果您使用 std::mt19937_64 a; std::mt19937_64 b; std::uniform_real_distribution<double> da; std::uniform_real_distribution<double> db; #pragma omp parallel for private(a, b) for (long i = 0; i < N; i++) { xs[i] = da(a); ys[i] = db(b); } 代替{{1},这可能会大大加快}}。对于每个生成的数字,这将只有32位的随机性,但这可能与mt19937产生的一样多。在64位系统/编译器上,期望mt19937_64运行速度一样快,并产生更大的随机性。

另一个小注:此处我只使用了每个生成器的默认种子(rand())。您可能希望随机生成种子,例如来自mt19937_64,并分别为每个线程的生成器播种,这样您就不会在线程之间重复数字。

答案 1 :(得分:0)

事实证明rand不是线程安全的。对于我试图使用的内容,一个简单的替代方法是drand48_r。如下更改我的循环显示了我期望的确切加速:

#pragma omp parallel for private(ii, rBuf, trand) shared(xs,ys)
    for(ii = 0; ii < N; ii++) {
        drand48_r(&rBuf, &trand);
        xs[ii] = trand;
        drand48_r(&rBuf, &trand);
        ys[ii] = trand;
    }