Is there an alternative to using time to seed a random number generation?
我尝试在计算集群中同时运行一段代码的几个实例(大约2000个实例)。它的工作方式是提交作业,集群将在节点打开时运行它们,每个节点有几个作业。这似乎为随机数生成中的大量实例生成相同的值,而这些实例使用时间种子。
有没有一个简单的替代品可以代替?可再生性和安全性并不重要,快速生成的独特种子是。最简单的方法是什么,如果可能的话,跨平台的方法是好的。
在Windows中,它可以通过
在GNU C中,可以通过以下方式访问:
1 2 3 4 5 | unsigned long long rdtsc(){ unsigned int lo,hi; __asm__ __volatile__ ("rdtsc" :"=a" (lo),"=d" (hi)); return ((unsigned long long)hi << 32) | lo; } |
指令测量处理器通电后的总伪周期。考虑到当今机器的高频率,即使两个处理器同时启动并以相同的速度计时,它们也极不可能返回相同的值。
1 2 3 4 | unsigned seed; read(open("/dev/urandom", O_RDONLY), &seed, sizeof seed); srand(seed); // IRL, check for errors, close the fd, etc... |
号
我还建议使用更好的随机数生成器。
PID和时间的组合应该足够获得一个独特的种子。它不是100%跨平台的,但是nix平台上的
号
您也可以在*nix系统上从
我假设您有一个启动其他进程的进程。把它传给种子使用。然后您可以让主进程为每个进程传入一个随机数作为其种子。这样一来,实际上只有一个任意的种子被选择…你可以用时间去做。
如果您没有启动其他进程的主进程,那么如果每个进程至少有一个唯一的索引,那么您可以做的是让一个进程在内存(如果共享内存)或文件(如果共享磁盘)中生成一系列随机数,然后让每个进程将该索引的第几个随机数拉出以用作其种子。
没有什么比一个种子中的一系列随机数更能使种子分布更均匀。
如果可以使用C++ 11,那么考虑EDCOX1×4。我建议你看链接以获得全面的指南。
从视频链接中提取基本信息:您不应使用
1 2 3 4 5 6 7 8 9 10 11 | #include <iostream> #include <random> int main() { std::random_device rd; std::mt19937 mt(rd()); std::uniform_int_distribution<int> dist(0,99); for (int i = 0; i < 16; i++) { std::cout << dist(mt) <<""; } std::cout << std::endl; } |
窗户
提供
您可以在msdn页面上找到文档。
Linux/Unix您可以使用openssl的
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 | #ifdef _WIN32 #include <NTSecAPI.h> #else #include <openssl/rand.h> #endif uint32_t get_seed(void) { uint32_t seed = 0; #ifdef _WIN32 RtlGenRandom(&seed, sizeof(uint32_t) ); #else RAND_bytes(&seed, sizeof(uint32_t) ); #endif return seed; } |
注意,openssl默认情况下提供了一个加密安全的prng,因此您可以直接使用它。更多信息。
只是个主意…生成一个guid(16个字节)并对其4个字节或8个字节的块求和(取决于种子的预期宽度),允许整数环绕。将结果用作种子。
guid通常封装生成它们的计算机的特性(如mac地址),这应该使得两台不同的机器最终生成相同的随机序列变得相当不可能。
这显然是不可移植的,但是为您的系统找到合适的API/库不应该太难(例如,在win32上的
不是用c std lib time()函数中以秒为单位测量的直接时间,而是使用处理器的计数器?大多数处理器都有一个自由运行的计时计数,例如在x86/x64中,有一个时间戳计数器:
The Time Stamp Counter is a 64-bit register present on all x86 processors since the Pentium. It counts the number of ticks since reset.
号
(该页面还有许多方法可以在不同的平台上访问这个计数器——gcc/ms-visual c/etc)
请记住,时间戳计数器并非没有缺陷,它可能无法跨处理器同步(您可能不关心您的应用程序)。省电功能可能会使处理器上下打卡(同样,你可能不在乎)。
如果唯一性很重要,您需要安排每个节点知道其他节点声明了什么ID。你可以用一个询问"有人认领身份证吗?"或者预先为每个节点安排一个尚未分配给其他节点的ID选择。
(guid使用机器的mac,因此属于"提前安排"类别。)
如果没有某种形式的协议,您将面临两个节点重叠相同ID的风险。
假设您使用的是一个合理的posix-ish系统,那么您应该使用