multithreading - 用于蒙特卡洛集成的线程安全随机数生成

标签 multithreading openmp random montecarlo

我正在尝试编写一些可以非常快速地计算随机数并且可以应用于多个线程的东西。我当前的代码是:

/* Approximating PI using a Monte-Carlo method. */

#include <stdio.h>
#include <stdlib.h>
#include <math.h>
#include <time.h>
#include <omp.h>
#define N 1000000000  /* As lareg as possible for increased accuracy */

double random_function(void);

int main(void)
{
   int i = 0;
    double X, Y;
   double count_inside_temp = 0.0, count_inside = 0.0;
   unsigned int th_id = omp_get_thread_num();
   #pragma omp parallel private(i, X, Y) firstprivate(count_inside_temp)
   {
      srand(th_id);
      #pragma omp for schedule(static)
      for (i = 0; i <= N; i++) {
         X = 2.0 * random_function() - 1.0;
         Y = 2.0 * random_function() - 1.0;
         if ((X * X) + (Y * Y) < 1.0) {
        count_inside_temp += 1.0;
     }
  }
  #pragma omp atomic
      count_inside += count_inside_temp;
   }
   printf("Approximation to PI is = %.10lf\n", (count_inside * 4.0)/ N);
   return 0;
}

double random_function(void)
{
   return ((double) rand() / (double) RAND_MAX);
}

这可行,但通过观察资源管理器,我知道它没有使用所有线程。 rand() 是否适用于多线程代码?如果没有,有没有好的选择?非常感谢。 jack

最佳答案

rand() 线程安全吗?也许,也许不是:

The rand() function need not be reentrant. A function that is not required to be reentrant is not required to be thread-safe."

一个测试和良好的学习练习是将对 rand() 的调用替换为一个固定整数,然后看看会发生什么。

我认为伪随机数生成器是一个黑盒子,它将一个整数作为输入并返回一个整数作为输出。对于任何给定的输入,输出总是相同的,但数字序列中没有模式,并且序列均匀分布在可能的输出范围内。 (这个模型不完全准确,但它会做到。)你使用这个黑盒子的方式是选择一个起始数字(种子)在你的应用程序中使用输出值并作为下一次调用的输入随机数发生器。设计 API 有两种常见的方法:

  1. 两个函数,一个用于设置初始种子(例如 srand(seed)),另一个用于从序列中检索下一个值(例如 rand())。 PRNG 的状态在内部存储在某种全局变量中。生成一个新的随机数要么不是线程安全的(很难说,但输出流将不可重现),要么在多线程代码中很慢(您最终会围绕状态值进行一些序列化)。
  2. PRNG 状态暴露给应用程序员的接口(interface)。这里通常有三个函数:init_prng(seed),返回 PRNG 状态的一些不透明表示;get_prng(state),返回随机数并更改状态变量,以及 destroy_peng(state),它只是清理分配的内存等等。具有此类 API 的 PRNG 都应该是线程安全的并且并行运行而无需锁定(因为您负责管理(现在是线程本地)状态变量。

我通常用 Fortran 编写并使用 Ladd's Mersenne Twister PRNG 的实现(该链接值得一读)。 C 中有很多合适的 PRNG,它们将状态公开给您控制。 PRNG看起来不错,使用它(在并行区域和私有(private)状态变量内进行初始化和销毁​​调用)应该会给你一个不错的加速。

最后,如果您一次性请求整个随机数序列(例如,编译器可以向量化 PRNG 内部结构),通常情况下可以使 PRNG 性能更好。因为这个库通常有类似 get_prng_array(state) 的函数,它会返回一个充满随机数的数组,就好像你把 get_prng 放在一个循环中填充数组元素一样 -他们只是做得更快。这将是第二次优化(并且需要在并行 for 循环内添加一个 for 循环。显然,您不希望这样做耗尽每个线程的堆栈空间!

关于multithreading - 用于蒙特卡洛集成的线程安全随机数生成,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/3772100/

相关文章:

java - java多线程回调

c++ - 在调用仿函数时删除它是否安全?

c++ - 英特尔线程构建模块性能不佳

c++ - 装修调度系统

c - 来自/dev/{random,urandom} 的快速并行随机数生成

php - 如何查找从随机表中选择的随机行

java - 构造后设置 Java 线程的 Runnable

Java 与主线程并行运行任务而不阻塞它

c++ - OpenMP 并行线程

vba - 如何理解因 RNG 播种过多而导致的自相关?