【发布时间】:2013-02-02 03:38:28
【问题描述】:
问题
我打算为 Linux 编写一个 C++11 应用程序,它基于大约一百万个伪随机 32 位数字进行一些数值模拟(不是密码学)。为了加快速度,我想使用桌面 CPU 的所有内核在并行线程中执行模拟。我想使用 boost 提供的 Mersenne Twister mt19937 作为 PRNG,我想出于性能原因,每个线程我应该有一个这样的 PRNG。现在我不确定如何播种它们以避免在多个线程中生成相同的随机数子序列。
替代方案
以下是我目前想到的替代方案:
-
独立于
/dev/urandom为每个线程播种 PRNG。我有点担心系统熵池耗尽的情况,因为我不知道系统内部 PRNG 是如何运行的。由于
/dev/urandom正在使用 Mersenne Twister 本身这一事实,我是否会意外地获得准确识别 Mersenne Twister 连续状态的连续种子?可能与我对下一点的担忧密切相关。 -
从
/dev/urandom播种一个 PRNG,从第一个播种其他 PRNG。基本上也是同样的问题:使用一个 PRNG 来播种另一个使用相同算法的 PRNG 是好还是坏?或者换句话说,从
mt19937读取 625 个 32 位整数是否直接对应于mt19937生成器在这一代期间的任何时候的内部状态? -
从一开始就用非梅森信息播种其他人。
由于使用相同的算法来生成随机数和生成初始种子在某种程度上感觉可能是个坏主意,因此我考虑引入一些不依赖于 Mersenne Twister 算法的元素。例如,我可以将线程 id 异或到初始种子向量的每个元素中。这会让事情变得更好吗?
-
在线程之间共享一个 PRNG。
这将确保只有一个序列具有 Mersenne Twister 的所有已知和理想特性。但是控制对该生成器的访问所需的锁定开销确实让我有些担心。由于我没有发现相反的证据,我假设我作为图书馆用户将负责防止对 PRNG 的并发访问。
-
预生成所有随机数。
这将使一个线程预先生成所有需要的 1M 随机数,供以后不同的线程使用。与整个应用程序相比,4M 的内存需求会很小。这种方法最让我担心的是随机数的生成本身并不是并发的。整个方法也不能很好地扩展。
问题
您会建议其中哪些方法,为什么?或者您有什么不同的建议?
您知道我的哪些担忧是有道理的,哪些仅仅是因为我对事情的实际运作缺乏洞察力吗?
【问题讨论】:
-
我之前也有同样的问题。 stackoverflow.com/questions/14804808/… 幸运的是我在使用 Java
-
@YankeeWhiskey,accepted answer there 在这里看起来像选项 3:您从由
SecureRandom生成的 UUID 播种它们,而SecureRandom又使用依赖于平台的熵源,而不仅仅是梅森捻线机。 -
所有建议的方法都将导致生成重复的随机数。通常,您从可能的 2**32 个数字中要求 2*20 个“随机”数字。这要求很多,因此您需要重新考虑您想要从 100 万个随机 32 位整数中获得哪些属性。如果唯一性是其中之一,那么这些方法都不起作用。
-
@GregS,个别重复的数字不会让我担心。我可能应该指定子序列长度的下限。我想说由两个线程精确复制的 10 个数字序列可能开始给我带来麻烦。但是 2**320 位的偶然巧合似乎不太可能,以至于我认为一旦两个线程有这么多共同的数字,它们可能也会有更多的共同点。
-
嗯,听起来您已经考虑过了,这很好。我担心的是生日悖论的结果。只要少数重复对你的算法来说不是致命的,你应该没问题。
标签: c++ multithreading boost random mersenne-twister