Как модифицировать член класса в multiprocessing.Pool.map?
Я пытаюсь распараллелить множественные вычисления численными методами. Есть функция, которая принимает скалярные значения x1
, x2
и вычисляет значение функции в этой точке. Значение функции необходимо найти в множестве точек. Поэтому я попытался разбить эти вычисления по ядрам.
Попытка №1. Создана функция calcSingle
, которая рассчитывает значение функции в заданной точке и сохраняет его в массиве - члене класса. Создана функция calc
, которая формирует сетку исходных данных и запускает многоядерный расчёт с помощью multiprocessing.Pool.map
.
class Solver(object):
def __init__(self):
self.mesh = np.zeros(0)
def calcSingle(self, *l):
(index, num), = l
self.mesh[index] = num
def calc(self):
self.x1, self.x2 = np.meshgrid(np.arange(1, 5), np.arange(5, 15))
self.mesh = np.zeros(self.x1.shape)
p = Pool(4)
p.map(self.calcSingle, zip(np.ndindex(self.mesh.shape), itertools.count(1)))
if __name__ == '__main__':
solver = Solver()
solver.calc()
print(solver.mesh)
Этот код выводит массив нулей. Вероятно, когда функция calcSingle
вызывается в отдельном процессе, self
ссылается уже на какой-то другой объект. Возможно, это происходит потому, что multiprocessing.Pool
повторно импортирует текущий модуль для каждого процесса. Тогда я стал искать информацию о передаче аргументов в функцию по ссылке. Такого, как оказалось, в Питоне нет, но есть рекомендации, что можно заворачивать требуемый аргумент в класс с одним атрибутом. По сути, класс Solver
и есть таковой класс, так почему бы не передать его в функцию calcSingle
?
Попытка №2.
class Solver(object):
def __init__(self):
self.mesh = np.zeros(0)
def calcSingle(self, *l):
(index, num, obj), = l
obj.mesh[index] = num
def calc(self):
self.x1, self.x2 = np.meshgrid(np.arange(1, 5), np.arange(5, 15))
self.mesh = np.zeros(self.x1.shape)
p = Pool(4)
p.map(self.calcSingle, zip(np.ndindex(self.mesh.shape), itertools.count(1), itertools.repeat(self)))
if __name__ == '__main__':
solver = Solver()
solver.calc()
print(solver.mesh)
Этот код порождает неконтролируемое количество процессов. Почему - не понимаю.
Конечно, можно заметить, что функция map
возвращает list
значений, возвращённых целевой функцией, и из него можно потом создать массив требуемой структуры. Но интересует именно модификация уже имеющегося массива, так как он может быть и memmap
.