我遇到了一件奇怪的事情:我写了一个模拟经济的程序。我没有在一个CPU核心上逐个运行这个模拟,而是希望使用多处理来加快速度。所以我运行我的代码(很好),我想从我正在进行的模拟中获得一些统计数据。然后出现了一个惊喜:同时完成的所有模拟产生了相同的结果! Pool()和random.seed()之间是否有一些奇怪的关系?
为了更清楚,以下是代码可以概括为:
class Economy(object):
def __init__(self,i):
self.run_number = i
self.Statistics = Statistics()
self.process()
def run_and_return(i):
eco = Economy(i)
return eco
collection = []
def get_result(x):
collection.append(x)
if __name__ == '__main__':
pool = Pool(processes=4)
for i in range(NRUN):
pool.apply_async(run_and_return, (i,), callback=get_result)
pool.close()
pool.join()
过程(i)是在i步骤期间经历模拟的每个步骤的功能。基本上我模拟了NRUN经济体,我从中获得了列入集合的统计数据。
现在奇怪的是,前4次运行的输出完全相同:在模拟的相同“波浪”期间,我得到了相同的输出。一旦我到达第二波,那么我将在接下来的4次模拟中获得不同的输出!
如果我使用相同的程序with processes = 1,所有这些模拟都运行良好:当我只在一个核心上工作时,我会得到不同的结果,逐个进行模拟......我尝试了一些东西,但不能让我的头围绕这个,因此我的帖子......
非常感谢您花时间阅读这篇长篇文章,请不要犹豫,要求更多精确!
一切顺利,
答案 0 :(得分:2)
如果您使用的是Linux,那么每个池进程都是通过分支父进程来完成的。这意味着该过程实际上是重复的 - 这包括任何随机对象可能正在使用的种子。
随机模块在导入时选择种子作为其默认函数。这意味着在创建池之前已经选择了种子。
要解决此问题,您必须为每个池进程使用初始化程序,将随机种子设置为唯一的。
种子random
的一个不错的方法是使用进程ID和当前时间。进程id必须在程序的单次运行中是唯一的。虽然使用时间将确保在多次运行中的唯一性,以防产生相同的过程ID。将进程id和时间作为字符串传递将意味着字符串的摘要也用于为随机数生成器播种 - 这意味着两个相似的字符串将产生实质上不同的种子。或者,您可以使用uuid
模块生成种子。
def proc_init():
random.seed(str(os.getpid()) + str(time.time()))
pool = Pool(num_procs, initializer=proc_init)