我正在使用MPICH2来实现"奇数-偶数"排序。我做了实现,但当我对每个过程随机化他的价值时,相同的数字被随机化到所有进程。
这是每个进程的代码,每个进程都随机化了自己的值。。
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);
并且它为每个进程提供不同的值:)
这个任务并不平凡。
由于使用time(0)
初始化srand()
,所以您得到的数字相同。time(0)
所做的是返回当前秒(自epoch以来)。因此,如果所有进程都具有同步时钟,那么只要它们在同一秒调用srand()
,所有进程都将使用相同的种子进行初始化,这是很有可能的。我甚至在大型机器上也观察到了这一点。
解决方案1。使用局部值初始化随机种子
我所做的是在计算随机种子时包括cat /proc/meminfo
和/dev/random
的一些内存使用情况,它们对物理机器来说比时钟更本地。请注意,对于1台机器上的N个任务,这可能仍然失败。但如果我没有记错的话,我也使用了task_id
。任何本地任务都足够了。把东西组合起来也是个好主意。毕竟,与实际计算相比,这些计算应该非常短。最好还是保持安全。
解决方案2。计算种子作为预处理步骤
您也可以使用您的方法从task 0
生成随机种子,并使用send-to-all
进行传播。尽管如此,当进行大规模(如10^5进程)时,它可能会出现扩展问题。您也可以使用任何其他方法来加载参数,并只准备种子作为预处理步骤。然而,它也涉及一些非琐碎的工作。
这是因为你的种子变化不够,随机性取决于你的种子。
来自srand
文档:
对于srand调用中使用的每个不同种子值伪随机数生成器可以预期生成不同的在随后对rand的调用中出现一系列结果。
编辑:尝试预先生成种子,或者为每个srand
调用手动更改种子。