2015-04-24 3 views
4

Я изучаю многопроцессорный модуль Python. У меня есть два случая:Генераторы случайных чисел в параллельных программах

Ex. 1

def Foo(nbr_iter): 
    for step in xrange(int(nbr_iter)) : 
     print random.uniform(0,1) 
... 

from multiprocessing import Pool 

if __name__ == "__main__": 
    ... 
    pool = Pool(processes=nmr_parallel_block) 
    pool.map(Foo, nbr_trial_per_process) 

Ex 2. (используя Numpy)

def Foo_np(nbr_iter): 
    np.random.seed() 
    print np.random.uniform(0,1,nbr_iter) 

В обоих случаях генераторы случайных чисел высевают в их раздвоенными процессах.

Почему я должен делать посев явно в примере numpy, но не в примере на Python?

+0

Пожалуйста, объясните, что заставляет вас думать, что вы * должны * – shx2

+0

Потому что, если я надену t, то каждый из разветвленных процессов будет генерировать идентичную последовательность случайных чисел (только в Ex.2) – overcomer

+0

, какая у вас ОС? – shx2

ответ

8

Если семя не указано явно, numpy.random будет семенами, используя источник случайности, зависящий от ОС. Обычно он будет использовать /dev/urandom в системах на базе Unix (или в некоторых эквивалентах Windows), но если это по какой-то причине недоступно, оно будет засеиваться с настенных часов. Так как самосеяние происходит в то время, когда новая подпроцессная вилка позволяет нескольким субпроцессам наследовать одно и то же семя, если они разветвляются в одно и то же время, что приводит к одинаковым случайным вариациям, создаваемым разными подпроцессами.

Часто это соотносится с количеством одновременных потоков, которые вы используете. Например:

import numpy as np 
import random 
from multiprocessing import Pool 

def Foo_np(seed=None): 
    # np.random.seed(seed) 
    return np.random.uniform(0, 1, 5) 

pool = Pool(processes=8) 
print np.array(pool.map(Foo_np, xrange(20))) 

# [[ 0.14463001 0.80273208 0.5559258 0.55629762 0.78814652] <- 
# [ 0.14463001 0.80273208 0.5559258 0.55629762 0.78814652] <- 
# [ 0.14463001 0.80273208 0.5559258 0.55629762 0.78814652] <- 
# [ 0.14463001 0.80273208 0.5559258 0.55629762 0.78814652] <- 
# [ 0.14463001 0.80273208 0.5559258 0.55629762 0.78814652] <- 
# [ 0.14463001 0.80273208 0.5559258 0.55629762 0.78814652] <- 
# [ 0.14463001 0.80273208 0.5559258 0.55629762 0.78814652] <- 
# [ 0.64672339 0.99851749 0.8873984 0.42734339 0.67158796] 
# [ 0.64672339 0.99851749 0.8873984 0.42734339 0.67158796] 
# [ 0.64672339 0.99851749 0.8873984 0.42734339 0.67158796] 
# [ 0.64672339 0.99851749 0.8873984 0.42734339 0.67158796] 
# [ 0.64672339 0.99851749 0.8873984 0.42734339 0.67158796] 
# [ 0.11283279 0.28180632 0.28365286 0.51190168 0.62864241] 
# [ 0.11283279 0.28180632 0.28365286 0.51190168 0.62864241] 
# [ 0.28917586 0.40997875 0.06308188 0.71512199 0.47386047] 
# [ 0.11283279 0.28180632 0.28365286 0.51190168 0.62864241] 
# [ 0.64672339 0.99851749 0.8873984 0.42734339 0.67158796] 
# [ 0.11283279 0.28180632 0.28365286 0.51190168 0.62864241] 
# [ 0.14463001 0.80273208 0.5559258 0.55629762 0.78814652] <- 
# [ 0.11283279 0.28180632 0.28365286 0.51190168 0.62864241]] 

Вы можете видеть, что группы до 8 потоков одновременно раздвоенные с тем же семени, давая мне одинаковые случайные последовательности (я пометил первую группу со стрелками).

Вызов np.random.seed() в подпроцессе заставляет локальный экземпляр RNG нить локализовать снова с /dev/urandom или настенные часы, которые (вероятно) не позволят вам видеть идентичный вывод из нескольких подпроцессов. Лучшая практика явно передать другое семя (или numpy.random.RandomState экземпляра) для каждого подпроцесса, например:

def Foo_np(seed=None): 
    local_state = np.random.RandomState(seed) 
    print local_state.uniform(0, 1, 5) 

pool.map(Foo_np, range(20)) 

Я не совсем уверен, что лежит в основе различия между random и numpy.random в этом отношении (возможно, он имеет немного отличается правила выбора источника случайности для самостоятельного семени по сравнению с numpy.random?). Я бы по-прежнему рекомендовал явно передавать семя или экземпляр random.Random для каждого подпроцесса, чтобы быть в безопасности. Вы также можете использовать метод .jumpahead()random.Random, который предназначен для перетасовки состояний экземпляров Random в многопоточных программах.

+0

Спасибо за ясный ответ – overcomer

+0

Я хочу поделиться случайным состоянием родительского процесса с дочерним процессом. Я пробовал использовать Менеджер, но все равно не повезло. Не могли бы вы взглянуть на мой вопрос [здесь] (https://stackoverflow.com/questions/49372619/how-to-share-numpy-random-state-of-a-parent-process-with-child-processes) и посмотреть, можете ли вы предложить решение? Я все еще могу получить разные случайные числа, если я делаю np.random.seed (None) каждый раз, когда я генерирую случайное число, но это не позволяет мне использовать случайное состояние родительского процесса, чего я не хочу. Любая помощь приветствуется. – Amir

Смежные вопросы