Python Multiprocessing - применить метод класса к списку объектов

Есть ли простой способ использовать многопроцессорность, чтобы сделать эквивалент этого?

for sim in sim_list:
  sim.run()

где элементы sim_list являются "моделирование" объекты и запуск() является методом класса моделирования, который делает изменение атрибутов объектов. Например:

class simulation:
    def __init__(self):
        self.state['done']=False
        self.cmd="program"
    def run(self):
        subprocess.call(self.cmd)
        self.state['done']=True

Все симы в sim_list независимы, поэтому стратегия не должна быть поточно-ориентированной.

Я попробовал следующее, что явно ошибочно, поскольку аргумент передается методом глубокой копии и не изменяется на месте.

from multiprocessing import Process

for sim in sim_list:
  b = Process(target=simulation.run, args=[sim])
  b.start()
  b.join()

Ответ 1

Один из способов сделать то, что вы хотите, - это сделать ваш вычислительный класс (simulation в вашем случае) подклассом Process. При правильной инициализации экземпляры этого класса будут запускаться в отдельных процессах, и вы можете выбрать группу из списка точно так же, как вы хотели.

Вот пример, основываясь на том, что вы написали выше:

import multiprocessing
import os
import random

class simulation(multiprocessing.Process):
    def __init__(self, name):
        # must call this before anything else
        multiprocessing.Process.__init__(self)

        # then any other initialization
        self.name = name
        self.number = 0.0
        sys.stdout.write('[%s] created: %f\n' % (self.name, self.number))

    def run(self):
        sys.stdout.write('[%s] running ...  process id: %s\n' 
                         % (self.name, os.getpid()))

        self.number = random.uniform(0.0, 10.0)
        sys.stdout.write('[%s] completed: %f\n' % (self.name, self.number))

Затем просто создайте список объектов и запустите каждый из них с помощью цикла:

sim_list = []
sim_list.append(simulation('foo'))
sim_list.append(simulation('bar'))

for sim in sim_list:
    sim.start()

Когда вы запустите это, вы увидите, как каждый объект запускается в своем собственном процессе. Не забудьте вызвать Process.__init__(self) как самое первое в инициализации вашего класса, прежде всего.

Очевидно, что в этом примере я не включил межпроцессное общение; вам придется добавить, что если ваша ситуация требует этого (из вашего вопроса было неясно, нужно ли вам это или нет).

Этот подход хорошо работает для меня, и я не знаю никаких недостатков. Если кто-нибудь знает о скрытых опасностях, которые я забыл, сообщите мне.

Надеюсь, это поможет.

Ответ 2

Для тех, кто будет работать с большими наборами данных, вам подойдет iterable:

import multiprocessing as mp
pool = mp.Pool(mp.cpu_count())
pool.imap(sim.start, sim_list)