问题
我打算根据大约一百万伪随机数32位写一个Linux C ++ 11的应用程序,做一些数值仿真(没有密码学)。 为了加快速度,我想在使用台式机CPU的所有内核并行线程执行仿真。 我想使用Mersenne扭曲mt19937
由升压提供的PRNG,我想,对于性能方面的原因,我应该有每个线程一个这样的PRNG。 现在我不知道如何播种它们,以避免产生在多线程随机数的相同的序列。
备择方案
下面是我想到的迄今为止选择:
种子PRNG从独立每个线程/dev/urandom
。
我有点担心的情况下,当系统的熵池被耗尽,因为我不知道系统内部PRNG如何操作。 这可能发生,我accidentially连续得到种子,其准确识别梅森倍捻机的连续状态,由于事实/dev/urandom
使用梅森难题本身? 大概是密切相关的我的顾虑下一个点。
从种子一个PRNG /dev/urandom
,并从第一个其他人。
基本上同样的关注,以及:这是好还是不好用一个PRNG种子另一个使用相同的算法? 或者换句话说,它读取从625个32位整数mt19937
直接对应的内部状态mt19937
在任何时候这一代中产生?
种子他人先用非梅森信息。
由于使用相同的算法来产生随机数并生成初始种子感觉莫名其妙地像它可能是一个坏主意,我想到了引入一些元素,它不依赖于梅森倍捻机算法。 例如,我可以XOR线程id到初始种子向量的每个元素。 这是否使事情变得更好?
共享一个PRNG线程之间。
这将确保只有一个序列,与梅森倍捻机的所有已知和期望的性能。 但锁定开销需要控制访问该发电机不担心我一些。 由于我没有发现任何证据,相反,我认为我作为图书馆用户将负责防止对PRNG的并发访问。
预生成所有的随机数。
这将有一个线程生成所有必需的1M随机数达阵,要由不同的线程以后使用。 4M的内存需求会相比,在整个应用程序的要小。 我最担心在这种方法的缺点是随机数本身的产生是不是并发。 这整个方法也没有规模太清楚了。
问题
哪些方法中,你会建议,为什么? 或者你有不同的建议吗?
你知道我的担心是有道理的,哪些只是由于我缺乏洞察事物是如何工作的?
我会用一个实例来播种人。 我敢肯定,你可以做到这一点安全很容易。
- 即使在状态空间的微小变化会导致相当大的变化下游 - 如果你能保证他们不具有完全相同的起始空间(没有等同的状态前缀),我就不会担心产生相同的数字。 例如,仅使用值1,2,3种子三个线程会很好地工作 - 你甚至都不需要种子的整个空间。 另一个优点:使用完全可以预测的种子,你可以很容易地抹黑的想法,你是樱桃采摘任何运行(假设你想要证明的东西)。
- 这是微不足道的,这意味着产生的“孩子”是高度不相关的方式播种。 只是在重复一个广度优先的方式; 也就是说,如果你希望种子的N×623种int类型,不按顺序种子623倍的值,但挑头N和分发,然后接下来的N等等。即使有播种机和儿童,之间的相关性有一定相关性不同的孩子应该是几乎不存在的 - 这就是你所关心的。
- 我宁愿一个算法,允许确定性执行只要有可能,所以根据 urandom的是没有吸引力。 这使得调试更加容易。
- 最后,显然 - 测试。 这些PRNG是相当强劲,但通过各种手段眼球的效果,做你所要模拟什么启发了一些相关的测试。 大多数问题应该是显而易见的 - 无论你播种严重并有明显的重复序列,你你已经播种好了,然后质量是由PRNG限制规定。
- 对于最终的执行,就大功告成了测试后,就可以播种的第一个使用urandom的的心境和/或线程ID的和平623个状态值。
我将与1号去的,从种子每urandom的PRNG。 这确保了状态是完全独立的(只要种子数据是独立的)。 通常会有很多的熵可用,除非你有多个线程。 另外,根据使用的/ dev / urandom的算法上,你几乎肯定不需要担心。
所以,你可能会使用类似以下内容创建每个PRNG:
#include <random>
std::mt19937 get_prng() {
std::random_device r;
std::seed_seq seed{r(), r(), r(), r(), r(), r(), r(), r()};
return std::mt19937(seed);
}
您应该确认您的实现std::random_device
从拉/dev/urandom
配置下。 如果它使用/ dev / urandom的默认那么通常你能说std::random_device("/dev/random")
如果你想使用/ dev /随机代替。
你可以使用一个PRNG具有不同代数结构播种不同的PRNG。 例如MD5散列的一些序列。
不过,我会选择#5。 如果它工作,然后它是好的。 如果没有,你仍然可以优化它。
该点是创造一个良好的 PRNG比人们所预料的要困难得多。 一个很好的PRNG为线程应用程序是最有可能的东西,依然受到研究。
如果CPU的数量足够低,你可以摆脱飞跃蛙式。 例如,如果你有4个内核,初始化所有具有相同的价值观,但提前核心1 PRNG 1,#2和#3 3.当你需要一个新的号码,然后总是提前4个步骤。
种子线程1用如图1所示,种子螺纹2 2等
如果您需要蒙特卡洛这会给你重复的结果,很容易跟踪和落实。
看看下面的纸: 伪随机数生成器的动态生成以及伴随的实现: 动态的创造者 。 它铲球这个确切的问题。
如果你真的想在数学上是正确的,使用由SFMT算法作者提供了跳跃功能。 跳转功能保证序列的两个不同的PRNG流之间的最小数目。
实事求是地讲,然而,一个的/ dev / urandom的初始化就足够了。
我会说#3是赢家。 籽有点像的ProcessID或线程ID每个线程; 虽然在技术上可以,你可以有重叠,这是极不可能。 即使是连续的数字不应该在种子方面,一旦你走出个位数(我不知道扭腰算法,但高于7我见过的最糟糕的PRNG被罚款)的有关。 相对于大多数PRNG方程的范围一分百万的PRNG是没有那么多。
最后,你可以检查很容易。 通过检查针对对方的所有线程数量每个线程产生的最后一个种子。 如果种子出现在螺纹,然后检查在每个线程中产生的先前的数; 如果他们也匹配,那么你有一个碰撞,需要重新播种您的视频流,然后再试一次。
有一个专门关于并行计算采用梅森倍捻机的实现(和发表的论文)。 它是由MT的原作者。 他们称其为“动态的创造者”,它可以在这里找到:
http://www.math.sci.hiroshima-u.ac.jp/~m-mat/MT/DC/dc.html
这将是一个非常好的地方学习您的MT19937的具体用法,尤其是纸那里。