Подтвердить что ты не робот

Выполните параллельный цикл for-loop в Python 3.2

Возможный дубликат:
как я могу распараллелить простой цикл python?

Я новичок в Python (используя Python 3.2), и у меня есть вопрос относительно параллелизации. У меня есть цикл for, который я хочу выполнить параллельно, используя "многопроцессорность" в Python 3.2:

def computation:    
    global output

    for x in range(i,j):
        localResult = ... #perform some computation as a function of i and j
        output.append(localResult)

В целом, я хочу выполнить это вычисление для диапазона от я = 0 до j = 100. Таким образом, я хочу создать несколько процессов, каждый из которых вызывает функцию "вычисление" с субдоменом всего диапазона. Любые идеи о том, как это сделать? Есть ли лучший способ, чем использование многопроцессорности?

Более конкретно, я хочу выполнить декомпозицию домена, и у меня есть следующий код:

from multiprocessing import Pool

class testModule:

    def __init__(self):
        self

    def computation(self, args):
        start, end = args
        print('start: ', start, ' end: ', end)

testMod = testModule()
length = 100
np=4
p = Pool(processes=np)
p.map(yes tMod.computation, [(length, startPosition, length//np) for startPosition in    range(0, length, length//np)]) 

Появляется сообщение об ошибке PicklingError. Любые идеи, что может быть проблемой здесь?

4b9b3361

Ответ 1

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

Простой случай выглядит примерно так:

from joblib import Parallel, delayed
Parallel(n_jobs=2)(delayed(foo)(i**2) for i in range(10))  # n_jobs = number of processes

Синтаксис прост, если вы его понимаете. Мы используем синтаксис генератора, в котором delayed используется для вызова функции foo с ее аргументами, содержащимися в круглых скобках.

В вашем случае вы должны либо переписать цикл for с синтаксисом генератора, либо определить другую функцию (например, функцию "работник" ) для выполнения операций одиночной итерации цикла и поместить это в синтаксис генератора вызова Parallel.

В последнем случае вы бы сделали что-то вроде:

Parallel(n_jobs=2)(delayed(foo)(parameters) for x in range(i,j))

где foo - это функция, которую вы определяете для обработки тела вашего цикла for. Обратите внимание, что вы не хотите добавлять в список, поскольку Parallel все равно возвращает список.

Ответ 2

В этом случае вы, вероятно, хотите определить простую функцию для выполнения вычисления и получить localResult.

def getLocalResult(args):
    """ Do whatever you want in this func.  
        The point is that it takes x,i,j and 
        returns localResult
    """
    x,i,j = args  #unpack args
    return doSomething(x,i,j)

Теперь в вашей вычислительной функции вы просто создаете пул работников и сопоставляете локальные результаты:

import multiprocessing
def computation(np=4):
    """ np is number of processes to fork """
    p = multiprocessing.Pool(np)
    output = p.map(getLocalResults, [(x,i,j) for x in range(i,j)] )
    return output

Я удалил глобальное здесь, потому что это ненужно (глобальные переменные обычно не нужны). В вашей процедуре вызова вы должны просто сделать output.extend(computation(np=4)) или что-то подобное.

ИЗМЕНИТЬ

Вот "рабочий" пример вашего кода:

from multiprocessing import Pool

def computation(args):
    length, startPosition, npoints = args
    print(args)

length = 100
np=4
p = Pool(processes=np)
p.map(computation, [(startPosition,startPosition+length//np, length//np) for startPosition in  range(0, length, length//np)])

Обратите внимание, что то, что у вас было, не работает, потому что вы использовали метод экземпляра в качестве своей функции. многопроцессорность запускает новые процессы и отправляет информацию между процессами через pickle, поэтому можно использовать только объекты, которые можно мариновать. Обратите внимание: в любом случае не имеет смысла использовать метод экземпляра. Каждый процесс является копией родителя, поэтому любые изменения состояния, которые происходят в процессах, в любом случае не распространяются на родителя.