5

我有一些并行的 Fortran90 代码,其中每个线程都需要生成相同的随机数序列。

我有一个似乎是线程不安全的随机数生成器,因为对于给定的种子,我完全无法在每次运行程序时重复相同的结果。

我(几乎)浏览了整个网络以寻找线程安全 RNG 的一些代码,但没有成功。任何人都可以向我提供(链接到)一个代码吗?

提前致谢!

4

8 回答 8

6

Fortran90的一个很好的伪随机数生成器可以在英特尔数学核心向量统计库中找到。它们是线程安全的。另外,为什么它需要是线程安全的?如果您希望每个线程获得相同的列表,请为每个具有相同种子的线程实例化一个新的 PRNG。

于 2009-03-02T13:59:35.463 回答
3

大多数可重复的随机数生成器需要某种形式的状态。没有状态,他们就无法做接下来的事情。为了线程安全,您需要一种方法来自己保持状态(即,它不能是全局的)。

于 2009-03-02T13:37:00.743 回答
2

当您说“需要生成相同的随机数序列”时,您的意思是

  • 每个线程都需要生成一个与另一个线程相同的数字流吗?这意味着在剥离线程之前选择种子,然后在每个线程中使用相同的种子实例化线程本地 PRNG。

或者

  • 您希望能够在程序的不同运行之间重复相同的数字序列,但每个线程生成它自己的独立序列?在这种情况下,您仍然无法共享单个 PRNG,因为线程操作顺序是不确定的。因此,在启动线程之前使用已知种子为单个 PRNG 播种,并使用它为线程生成初始种子。然后在每个线程中实例化线程本地生成器......

在每种情况下,您都应该注意Neil Butterworth对统计数据的看法:当以这种方式生成混合流时,PRNG 喜欢声称的大多数通常保证都不可靠。


在这两种情况下,您都需要一个线程本地 PRNG。我不知道 f90 中有什么可用...但您也可以自己编写(查找Mersenne Twister,并编写一个将保存状态作为参数的例程...)。

在 fortran 77 中,这看起来像

      function PRNGthread (state)

      double state(statesize)

c stuff happens here which uses and manipulates the state vector...

      PRNGthread = result
      return 

并且您的每个线程都应该维护一个单独的状态向量,尽管所有线程都将使用相同的初始值。

于 2009-03-02T16:11:27.127 回答
1

我了解您需要每个线程来产生相同的随机数流。

MT19937是一个非常好的 Pseudo Random Generator,它可以生成可重现的数字流并且速度非常快。只需确保在产生线程之前生成种子,但在每个线程中生成一个单独的 MT 实例(使 MT 线程的实例本地化)。这样就可以保证每个 MT 都会产生相同的数字流。

于 2009-03-02T16:23:10.313 回答
1

SPRNG怎么样?我自己还没有尝试过。

于 2009-03-02T17:20:28.053 回答
1

我编写了 Mersenne Twister/MT19973 的线程安全 Fortran 90 版本。PRNG 的状态保存在派生类型 (randomNumberSequence) 中,您可以使用过程为生成器播种或获取序列中的下一个元素。

请参阅http://code.google.com/p/i3rc-monte-carlo-model/source/browse/trunk/Code/RandomNumbersForMC.f95

于 2010-03-06T04:08:58.253 回答
0

替代方案似乎是:

  • 在生成器的种子值上使用同步对象(例如互斥锁)。不幸的是,这将在访问生成器时序列化您的代码
  • 在生成器中使用线程本地存储,以便每个线程都有自己的种子 - 这可能会导致您的应用出现统计问题
  • 如果您的平台支持合适的原子操作,请在种子上使用它(但它可能不会)

我知道,这不是一个非常令人鼓舞的清单。除此之外,我不知道如何在 FORTRAN 中实现它们中的任何一个!

于 2009-03-02T13:43:45.610 回答
0

这篇文章https://www.cmiss.org/openCMISS/wiki/RandomNumberGenerationWithOpenMP不仅链接到 Fortran 实现,还提到了使 PRNG 可用于线程所需的关键点。最重要的一点是:

Fortran90 版本的 Ziggurat 有几个带有“SAVE”属性的变量和数组。为了使统一的 RNG 并行化,似乎所需的更改是使这些变量数组具有每个线程的单独值(谨防错误共享)。那么当调用PRNG函数时,我们必须传递线程号,并使用对应的状态值。

于 2019-02-18T17:45:22.953 回答