Python多处理:多次执行具有随机性的函数,得到相同的结果



在下面的示例代码中,我试图在这个线程中调整已接受的答案。目标是使用多重处理来生成独立的随机正规数(在下面的例子中,我只想要3个随机数(。这是任何更复杂代码的婴儿版本,其中一些随机数生成器用于定义试验函数。

示例代码

import multiprocessing
def trial(procnum, return_dict):
p = np.random.randn(1)
num = procnum
return_dict[procnum] = p, num
if __name__ == '__main__':
manager = multiprocessing.Manager()
return_dict = manager.dict()
jobs = []
for i in range(5):
p = multiprocessing.Process(target=trial, args=(i,return_dict))
jobs.append(p)
p.start()
for proc in jobs:
proc.join()
print(return_dict.values())

但是,输出每次都给我相同的随机数,而不是return_dict中每个条目的独立随机数。

输出

[(array([-1.08817286]), 0), (array([-1.08817286]), 1), (array([-1.08817286]), 2)]

我觉得这是一个非常愚蠢的错误。有人能揭露我的愚蠢吗?(

这不是一个愚蠢的错误,它与numpy跨核心进行转移的方式有关。点击此处阅读更多信息:https://discuss.pytorch.org/t/why-does-numpy-random-rand-produce-the-same-values-in-different-cores/12005

但解决方案是给numpy一个大范围的随机种子:

import multiprocessing
import numpy as np
import random
def trial(procnum, return_dict):
np.random.seed(random.randint(0,100000))
p = np.random.randn()
return_dict[procnum] = p
if __name__ == '__main__':
manager = multiprocessing.Manager()
return_dict = manager.dict()
jobs = []
for i in range(3):
p = multiprocessing.Process(target=trial, args=(i,return_dict))
jobs.append(p)
p.start()
for proc in jobs:
proc.join()
print(return_dict.values())

只是为@Aziz Sonawala的答案添加了一个亮点:为什么这有效?

因为Python的random模块的工作方式不同。在Windows上,多处理产生了新的进程,每个进程都是一个新创建的实例,它从操作系统的熵源开始进行自己的从头开始的播种。

在Linux上,默认情况下,多处理使用fork()创建新进程,并且这些进程在写时复制模式下继承主进程的整个状态。这包括随机数生成器的状态。因此,也会在Python的工作进程中获得相同的随机数,只是至少从Python 3.7开始,Python在fork()之后显式地(但在隐蔽的情况下——无形地(重新播种其随机数生成器。

我不确定是什么时候,但在3.7之前的一段时间里,多处理Process实现也在它通过fork()创建的子进程中重新播种了Python的生成器(但如果您自己调用fork(),Python本身会而不是(。

所有这些只是为了解释为什么调用Python的random.randrange()会在不同的工作进程中返回不同的结果。这就是为什么它是生成不同种子供numpy在这种情况下使用的有效方法。

相关内容

  • 没有找到相关文章

最新更新