Установка случайного начального числа в Python мешает многопроцессорности - PullRequest
0 голосов
/ 04 июня 2018

Я заметил, что установка случайного начального числа перед использованием многопроцессорной обработки в python вызывает странное поведение.

В python 3.5.2 используются только 2 или 3 ядра с низким процентом используемого ЦП.В python 2.7.13 все запрошенные ядра используются на 100%, но код, кажется, никогда не завершается.Когда я удаляю инициализацию случайного начального числа, распараллеливание работает нормально.

Это происходит, даже если в распараллеленной функции нет явного использования random.Теперь я предполагаю, что начальное число распределяется между процессами, что препятствует бесперебойной работе многопроцессорных систем, но может ли кто-нибудь дать правильный ответ?


Я запустил код в Linux и вот минимальный пример кода:

from multiprocessing import Pool
import numpy as np
import random

random.seed = 2018

NB_CPUS = 4

def test(x):
    return x**2

pool = Pool(NB_CPUS)
args = [np.random.rand() for _ in range(100000)]

results = pool.map(test, args)

pool.terminate()
results[-5:]

1 Ответ

0 голосов
/ 07 мая 2019

С опозданием с ответом, но вы ломаете голову, устанавливая для random.seed функцию значение int.Вместо этого вы должны сделать:

random.seed(2018)

последние несколько строк трассировки обеспечивают контекст, который должен был сделать это очевидным:

  File "/usr/lib64/python2.7/multiprocessing/process.py", line 130, in start
    self._popen = Popen(self)
  File "/usr/lib64/python2.7/multiprocessing/forking.py", line 125, in __init__
    random.seed()
TypeError: 'int' object is not callable

это заставляет Pool продолжать пытаться создатьновые рабочие процессы, но так как это происходит каждый раз, когда невозможно продвинуться вперед.

За этим стоит то, что multiprocessing знает, что он должен повторно заполнить случайный модуль при разветвлении, чтобы дочерние процессы не разделялито же состояние RNG.Для этого он пытается вызвать функцию random.seed, но вы установили для нее значение int, которое не вызывается - отсюда и ошибка!

Другая проблема, связанная с этим, заключается в том, что multiprocessing не знает, чтобы заново заполнить NumPy RNG, поэтому следующий код:

from multiprocessing import Pool
import numpy as np

def test(i):
    print(i, np.random.rand())

with Pool(4) as pool:
    pool.map(test, range(4))

заставит каждого работника печатать одно и то же значение. Эта проблема известна давно, но все еще остается открытой.Вы можете обойти это, используя рабочий initializer, например:

def initfn():
    np.random.seed()

with Pool(4, initializer=initfn) as pool:
    pool.map(test, range(4))

теперь заставит вышеуказанную функцию test печатать различные значения.Обратите внимание, что вы даже можете использовать Pool(4, initializer=np.random.seed), если не выполняете никакой другой инициализации рабочего уровня.

...