我正在使用MPICH2来实现“Odd-Even”排序。 我做了实现但是当我随机化到每个进程他的价值时, 相同的数字随机分配给所有进程。
以下是每个流程的代码,每个流程随机化他的值..
int main(int argc,char *argv[])
{
int nameLen, numProcs, myID;
char processorName[MPI_MAX_PROCESSOR_NAME];
int myValue;
MPI_Init(&argc,&argv);
MPI_Comm_rank(MPI_COMM_WORLD,&myID);
MPI_Comm_size(MPI_COMM_WORLD,&numProcs);
MPI_Get_processor_name(processorName,&nameLen);
MPI_Status status;
srand((unsigned)time(NULL));
myValue = rand()%30+1;
cout << "myID: " << myID << " value: " << myValue<<endl;
MPI_Finalize();
return 0;
}
为什么每个进程都获得相同的值?
编辑:感谢答案:)
我改变了行
srand((unsigned)time(NULL));
到
srand((unsigned)time(NULL)+myID*numProcs + nameLen);
并为每个进程提供不同的值:)
答案 0 :(得分:6)
这项任务并非无足轻重。
由于您使用srand()
初始化time(0)
,因此获得相同的数字。 time(0)
做的是返回当前秒(自纪元以来)。因此,如果所有进程都具有同步时钟,则只要它们在同一秒钟内调用srand()
,所有进程都将使用相同的种子初始化,这很可能。我甚至在大型机器上都观察到了这一点。
解决方案1.使用本地值初始化随机种子。
我所做的是将cat /proc/meminfo
与/dev/random
结合使用的一些内存使用量计算在随机种子中,这些内存使用比物理机器更本地化。请注意,对于1台计算机上的N个任务,这可能仍会失败。但如果我没记错的话,我也使用了task_id
。任何本地任务就足够了。结合东西也是个好主意。毕竟这些计算与实际计算相比应该非常短。最好是保持安全。
解决方案2.计算种子作为预处理步骤。
您还可以使用您的方法从task 0
生成随机种子,并使用send-to-all
传播它。但是,当进行大规模(例如10 ^ 5个进程)时,它可能会出现扩展问题。您还可以使用任何其他方法来加载参数,并准备种子作为预处理步骤。然而,它也涉及一些非平凡的工作。
答案 1 :(得分:2)
这是因为你的种子没有足够的变化,随机性取决于你的种子。
来自srand
docs:
对于调用srand时使用的每个不同的种子值, 可以预期伪随机数发生器产生不同的 在随后的rand调用中继续产生结果。
编辑:尝试预先生成种子,或者为每{{}}}次呼叫手动更改种子。