Я новичок в модуле фьючерсов, и у меня есть задача, которая может выиграть от распараллеливания; но я, кажется, не могу понять, как именно настроить функцию для потока и функцию для процесса. Я был бы признателен за любую помощь, которую может пролить каждый.
Я использую оптимизацию роя частиц (PSO). Не вдаваясь в подробности о самом PSO, вот основная схема моего кода:
Существует класс Particle
с методом getFitness(self)
(который вычисляет некоторую метрику и сохраняет ее в self.fitness
). Симуляция PSO имеет несколько экземпляров частиц (более 10; 100 или даже 1000 для некоторых симуляций).
Время от времени мне приходится вычислять физическую форму частиц. В настоящее время я делаю это в цикле:
for p in listOfParticles:
p.getFitness(args)
Тем не менее, я замечаю, что пригодность каждой частицы может быть вычислена независимо друг от друга. Это делает это вычисление пригодности главным кандидатом для распараллеливания. Действительно, я мог бы сделать map(lambda p: p.getFitness(args), listOfParticles)
.
Теперь я легко могу сделать это с помощью futures.ProcessPoolExecutor
:
with futures.ProcessPoolExecutor() as e:
e.map(lambda p: p.getFitness(args), listOfParticles)
Поскольку побочные эффекты вызова p.getFitness
хранятся в каждой частице, мне не нужно беспокоиться о получении отдачи от futures.ProcessPoolExecutor()
.
Все идет нормально. Но теперь я замечаю, что ProcessPoolExecutor
создает новые процессы, что означает, что он копирует память, что медленно. Я хотел бы иметь возможность делиться памятью - поэтому я должен использовать потоки. Это хорошо, пока я не пойму, что запуск нескольких процессов с несколькими потоками внутри каждого процесса, скорее всего, будет быстрее, поскольку несколько потоков все еще работают только на одном процессоре моей замечательной 8-ядерной машины.
Здесь, где я сталкиваюсь с неприятностями:
На основании примеров, которые я видел, ThreadPoolExecutor
работает на list
. Так же как и ProcessPoolExecutor
. Поэтому я не могу сделать ничего итеративного в ProcessPoolExecutor
, чтобы перейти на ThreadPoolExecutor
, потому что тогда ThreadPoolExecutor
собирается заставить работать один объект (см. мою попытку, опубликованную ниже).
С другой стороны, я не могу сам нарезать listOfParticles
, потому что я хочу, чтобы ThreadPoolExecutor
делал свою собственную магию, чтобы выяснить, сколько потоков требуется.
Итак, большой вопрос (наконец-то):
Как я должен структурировать свой код так, чтобы я мог эффективно распараллеливать следующее, используя оба процесса и потоки:
for p in listOfParticles:
p.getFitness()
Это то, что я пытался, но я не осмелился бы попытаться запустить его, потому что я знаю, что это не сработает:
>>> def threadize(func, L, mw):
... with futures.ThreadpoolExecutor(max_workers=mw) as executor:
... for i in L:
... executor.submit(func, i)
...
>>> def processize(func, L, mw):
... with futures.ProcessPoolExecutor() as executor:
... executor.map(lambda i: threadize(func, i, mw), L)
...
Буду признателен за любые мысли о том, как это исправить, или даже о том, как улучшить мой подход
.В случае, если это имеет значение, я на Python3.3.2