如何并行生成随机数?[英] How to generate random numbers in parallel?

本文是小编为大家收集整理的关于如何并行生成随机数?的处理方法,想解了如何并行生成随机数?的问题怎么解决?如何并行生成随机数?问题的解决办法?那么可以参考本文帮助大家快速定位并解决问题。

问题描述

我想使用OpenMP并行生成伪数字,类似的东西:

int i;
#pragma omp parallel for
for (i=0;i<100;i++)
{
    printf("%d %d %d\n",i,omp_get_thread_num(),rand());
} 
return 0; 

我已经在Windows上进行了测试,并且我的加速度很大,但是每个线程都会生成完全相同的数字.我也在Linux上进行了测试,我的放缓幅度很大,在8核处理器上的并行版本比顺序慢10次,但是每个线程都会生成不同的数字.

有什么方法可以同时具有加速和不同的数字?

编辑27.11.2010
我认为我已经使用Jonathan Dursi Post的想法解决了它.似乎以下代码在Linux和Windows上都可以很快.数字也是伪随机.您如何看待它?

int seed[10];

int main(int argc, char **argv) 
{
int i,s;
for (i=0;i<10;i++)
    seed[i] = rand();

#pragma omp parallel private(s)
{
    s = seed[omp_get_thread_num()];
    #pragma omp for
    for (i=0;i<1000;i++)
    {
        printf("%d %d %d\n",i,omp_get_thread_num(),s);
        s=(s*17931+7391); // those numbers should be choosen more carefully
    }
    seed[omp_get_thread_num()] = s;
}
return 0; 
} 

ps.:我还没有接受任何答案,因为我需要确保这个想法很好.

推荐答案

我将在这里发布我发布的内容,我发布到 conterrent随机数生成:

我认为您正在寻找rand_r(),它明确将当前的RNG状态作为参数.那么每个线程都应具有自己的种子数据副本(无论您希望每个线程以相同的种子开头还是不同的种子都取决于您的工作,您都希望它们与众不同,否则您将获得相同的行一次又一次).这里有一些讨论Rand_r()和线程安全: rand_r是否真实线程安全?.

因此,说您希望每个线程都以其线程号启动其种子(这可能不是您想要的,因为每次您使用相同数量的线程都会给出相同的结果,但就像一个示例):

#pragma omp parallel default(none)
{
    int i;
    unsigned int myseed = omp_get_thread_num();
    #pragma omp for
    for(i=0; i<100; i++)
            printf("%d %d %d\n",i,omp_get_thread_num(),rand_r(&myseed));
}

编辑:就在百灵鸟上,检查以上是否会得到任何加速.完整代码为

#define NRANDS 1000000
int main(int argc, char **argv) {

    struct timeval t;
    int a[NRANDS];

    tick(&t);
    #pragma omp parallel default(none) shared(a)
    {
        int i;
        unsigned int myseed = omp_get_thread_num();
        #pragma omp for
        for(i=0; i<NRANDS; i++)
                a[i] = rand_r(&myseed);
    }
    double sum = 0.;
    double time=tock(&t);
    for (long int i=0; i<NRANDS; i++) {
        sum += a[i];
    }
    printf("Time = %lf, sum = %lf\n", time, sum);

    return 0;
}

tick和tock只是包装器gettimeofday(),而tock()返回秒的差异.打印总和只是为了确保没有任何优化,并证明一个小点;您将获得具有不同数字线程的不同数字,因为每个线程都将其自己的线程作为种子.如果您一次又一次使用相同数量的线程运行相同的代码,则出于相同的原因,您将获得相同的总和.无论如何,计时(在没有其他用户的8核Nehalem盒子上运行):

$ export OMP_NUM_THREADS=1
$ ./rand
Time = 0.008639, sum = 1074808568711883.000000

$ export OMP_NUM_THREADS=2
$ ./rand
Time = 0.006274, sum = 1074093295878604.000000

$ export OMP_NUM_THREADS=4
$ ./rand
Time = 0.005335, sum = 1073422298606608.000000

$ export OMP_NUM_THREADS=8
$ ./rand
Time = 0.004163, sum = 1073971133482410.000000

如此加速,即使不是很好;正如@Ruslik指出的那样,这实际上并不是一个计算密集的过程,并且其他问题等问题开始扮演角色.因此,在8个内核上仅超过2倍的速度.

其他推荐答案

您无法使用多个线程的C rand()函数;这导致不确定的行为.某些实现可能会使您锁定(这会使之慢);其他人可能会允许线程互相抓住彼此的状态,可能会崩溃您的程序或仅给出"不良"随机数.

要解决问题,要么编写您自己的PRNG实现,要么使用现有的实现问题,该实现允许呼叫者存储并将状态传递给PRNG ITERATOR函数.

其他推荐答案

获取每个线程根据其线程ID设置不同的种子,例如srand(omp_get_thread_num() * 1000);

本文地址:https://www.itbaoku.cn/post/359227.html

相关标签/搜索