Парфор для Питона - PullRequest
       7

Парфор для Питона

44 голосов
/ 13 января 2011

Я ищу окончательный ответ на парфоре MATLAB для Python (Scipy, Numpy).

Есть ли решение, похожее на парфор?Если нет, в чем сложность его создания?

ОБНОВЛЕНИЕ: Вот типичный код числового вычисления, который мне нужно ускорить

import numpy as np

N = 2000
output = np.zeros([N,N])
for i in range(N):
    for j in range(N):
        output[i,j] = HeavyComputationThatIsThreadSafe(i,j)

Пример тяжелой функции вычисления:

import scipy.optimize

def HeavyComputationThatIsThreadSafe(i,j):
    n = i * j

    return scipy.optimize.anneal(lambda x: np.sum((x-np.arange(n)**2)), np.random.random((n,1)))[0][0,0]

Ответы [ 6 ]

27 голосов
/ 13 января 2011

Один из встроенных в Python будет multiprocessing документы здесь здесь . Я всегда использую multiprocessing.Pool с таким количеством рабочих, сколько процессоров. Тогда всякий раз, когда мне нужно сделать структуру, похожую на цикл, я использую Pool.imap

Пока тело вашей функции не зависит от какой-либо предыдущей итерации, у вас должно быть почти линейное ускорение. Для этого также требуется, чтобы ваши входы и выходы были pickle -безопасными, но это довольно легко гарантировать для стандартных типов.

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

from multiprocessing import Pool
from itertools import product

output = np.zeros((N,N))
pool = Pool() #defaults to number of available CPU's
chunksize = 20 #this may take some guessing ... take a look at the docs to decide
for ind, res in enumerate(pool.imap(Fun, product(xrange(N), xrange(N))), chunksize):
    output.flat[ind] = res
19 голосов
/ 13 января 2011

Существует множество сред Python для параллельных вычислений . Больше всего мне нравится IPython , но я не знаю много о других. В IPython одним аналогом parfor будет client.MultiEngineClient.map() или некоторые другие конструкции в документации по быстрому и простому параллелизму .

4 голосов
/ 19 ноября 2017

Jupyter Notebook

Чтобы увидеть пример, вы хотите написать эквивалент этого кода Matlab на Python

matlabpool open 4
parfor n=0:9
   for i=1:10000
       for j=1:10000
           s=j*i   
       end
   end
   n
end
disp('done')

Способ, которым можно написать это на python, особенно в jupyter notebook,Вы должны создать функцию в рабочем каталоге (я назвал ее FunForParFor.py), которая имеет следующий код:

def func(n):
    for i in range(10000):
        for j in range(10000):
            s=j*i
    print(n)

Затем я иду в свой блокнот Jupyter и пишу следующий код

import multiprocessing  
import FunForParFor

if __name__ == '__main__':
    pool = multiprocessing.Pool(processes=4)
    pool.map(FunForParFor.func, range(10))
    pool.close()
    pool.join()   
    print('done')

Это сработало для меня!Я просто хотел поделиться этим здесь, чтобы дать вам конкретный пример.

4 голосов
/ 13 января 2011

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

2 голосов
/ 04 февраля 2019

Это можно сделать элегантно с Ray , системой, которая позволяет вам легко распараллеливать и распространять ваш код Python.

Чтобы распараллелить ваш пример, вам нужно определить свои функции с помощью декоратора @ray.remote, а затем вызвать их с помощью .remote.

import numpy as np
import time

import ray

ray.init()

# Define the function. Each remote function will be executed 
# in a separate process.
@ray.remote
def HeavyComputationThatIsThreadSafe(i, j):
    n = i*j
    time.sleep(0.5) # Simulate some heavy computation. 
    return n

N = 10
output_ids = []
for i in range(N):
    for j in range(N):
        # Remote functions return a future, i.e, an identifier to the 
        # result, rather than the result itself. This allows invoking
        # the next remote function before the previous finished, which
        # leads to the remote functions being executed in parallel.
        output_ids.append(HeavyComputationThatIsThreadSafe.remote(i,j))

# Get results when ready.
output_list = ray.get(output_ids)
# Move results into an NxN numpy array.
outputs = np.array(output_list).reshape(N, N)

# This program should take approximately N*N*0.5s/p, where
# p is the number of cores on your machine, N*N
# is the number of times we invoke the remote function,
# and 0.5s is the time it takes to execute one instance
# of the remote function. For example, for two cores this
# program will take approximately 25sec. 

Существует ряд преимуществ использования Ray по сравнению с многопроцессорным модулем . В частности, тот же код будет работать как на одной машине, так и на кластере машин. Для получения дополнительных преимуществ Рэй см. этот пост .

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

1 голос
/ 13 сентября 2018

Я перепробовал все решения здесь, но обнаружил, что самый простой способ и самый близкий эквивалент matlabs parfor это pumb * numba's

.

По сути, вы меняете одну букву в цикле, диапазон до prange:

from numba import autojit, prange

@autojit
def parallel_sum(A):
    sum = 0.0
    for i in prange(A.shape[0]):
        sum += A[i]

    return sum
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...