Такая же производительность у разных работников в многопроцессорной обработке
У меня очень простые случаи, когда работа, которая должна быть выполнена, может быть разбита и распределена между рабочими. Я попробовал очень простой многопроцессорный пример из здесь:
import multiprocessing
import numpy as np
import time
def do_calculation(data):
rand=np.random.randint(10)
print data, rand
time.sleep(rand)
return data * 2
if __name__ == '__main__':
pool_size = multiprocessing.cpu_count() * 2
pool = multiprocessing.Pool(processes=pool_size)
inputs = list(range(10))
print 'Input :', inputs
pool_outputs = pool.map(do_calculation, inputs)
print 'Pool :', pool_outputs
Вышеуказанная программа выводит следующий результат:
Input : [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
0 7
1 7
2 7
5 7
3 7
4 7
6 7
7 7
8 6
9 6
Pool : [0, 2, 4, 6, 8, 10, 12, 14, 16, 18]
Почему одно и то же случайное число печатается? (У меня 4 процессора в моей машине). Это лучший/самый простой способ продвижения вперед?
Ответы
Ответ 1
Думаю, вам нужно повторно засеять генератор случайных чисел, используя numpy.random.seed в вашей функции do_calculation
.
Моя догадка заключается в том, что генератор случайных чисел (RNG) получает сеяние при импорте модуля. Затем, когда вы используете многопроцессорную обработку, вы форкируете текущий процесс с уже засеянным RNG. Таким образом, все ваши процессы используют одно и то же начальное значение для RNG и поэтому будут генерировать те же последовательности чисел.
например:.
def do_calculation(data):
np.random.seed()
rand=np.random.randint(10)
print data, rand
return data * 2
Ответ 2
В этом блоге приведен пример хорошей и плохой практики при использовании numpy.random и мультиобработки. Более важно понять, когда создается начальное число вашего генератора псевдослучайных чисел (PRNG):
import numpy as np
import pprint
from multiprocessing import Pool
pp = pprint.PrettyPrinter()
def bad_practice(index):
return np.random.randint(0,10,size=10)
def good_practice(index):
return np.random.RandomState().randint(0,10,size=10)
p = Pool(5)
pp.pprint("Bad practice: ")
pp.pprint(p.map(bad_practice, range(5)))
pp.pprint("Good practice: ")
pp.pprint(p.map(good_practice, range(5)))
выход:
'Bad practice: '
[array([4, 2, 8, 0, 1, 1, 6, 1, 2, 9]),
array([4, 2, 8, 0, 1, 1, 6, 1, 2, 9]),
array([4, 2, 8, 0, 1, 1, 6, 1, 2, 9]),
array([4, 2, 8, 0, 1, 1, 6, 1, 2, 9]),
array([4, 2, 8, 0, 1, 1, 6, 1, 2, 9])]
'Good practice: '
[array([8, 9, 4, 5, 1, 0, 8, 1, 5, 4]),
array([5, 1, 3, 3, 3, 0, 0, 1, 0, 8]),
array([1, 9, 9, 9, 2, 9, 4, 3, 2, 1]),
array([4, 3, 6, 2, 6, 1, 2, 9, 5, 2]),
array([6, 3, 5, 9, 7, 1, 7, 4, 8, 5])]
В хорошей практике начальное число создается один раз для каждого потока, в то время как в плохой практике начальное число создается только один раз при импорте модуля numpy.random.