问题
我打算为 Linux 编写一个 C++11 应用程序,它基于大约一百万个伪随机 32 位数字进行一些数值模拟(不是密码学)。为了加快速度,我想使用桌面 CPU 的所有内核在并行线程中执行模拟。我想使用mt19937
boost 提供的 Mersenne Twister 作为 PRNG,我想出于性能原因,我应该每个线程都有一个这样的 PRNG。现在我不确定如何播种它们以避免在多个线程中生成相同的随机数子序列。
备择方案
以下是我到目前为止想到的替代方案:
为每个线程独立播种 PRNG
/dev/urandom
。我有点担心系统熵池耗尽的情况,因为我不知道系统内部 PRNG 是如何运行的。
/dev/urandom
由于使用 Mersenne Twister 本身的事实,我是否会意外地获得准确识别 Mersenne Twister 连续状态的连续种子?可能与我对下一点的担忧密切相关。从第一个中播种一个 PRNG,
/dev/urandom
另一个从第一个中播种。基本上也是同样的问题:使用一个 PRNG 来播种另一个使用相同算法的 PRNG 是好还是坏?或者换句话说,从 a 中读取 625 个 32 位整数是否
mt19937
直接对应于mt19937
生成器在这一代期间的任何时候的内部状态?从一开始就用非梅森信息播种其他人。
由于使用相同的算法来生成随机数和生成初始种子感觉好像是个坏主意,所以我考虑引入一些不依赖于 Mersenne Twister 算法的元素。例如,我可以将线程 id 异或到初始种子向量的每个元素中。这会让事情变得更好吗?
在线程之间共享一个 PRNG。
这将确保只有一个序列具有 Mersenne Twister 的所有已知和理想特性。但是控制对该生成器的访问所需的锁定开销确实让我有些担心。由于我没有发现相反的证据,我假设我作为图书馆用户将负责防止对 PRNG 的并发访问。
预先生成所有随机数。
这将有一个线程预先生成所有需要的 1M 随机数,以便稍后由不同的线程使用。与整个应用程序相比,4M 的内存需求会很小。这种方法最让我担心的是随机数的生成本身并不是并发的。整个方法也不能很好地扩展。
问题
您会建议哪种方法,为什么?或者你有什么不同的建议?
你知道我的哪些担忧是有道理的,哪些仅仅是因为我对事情的实际运作缺乏洞察力吗?