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

45

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

Есть ли решение, подобное parfor? Если нет, то каково усложнение для его создания?

UPDATE: Вот типичный цифровой вычислительный код, который мне нужно ускорить

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]
Теги:
parallel-processing

6 ответов

19
Лучший ответ

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

  • 1
    +1 Не знал о клиенте. MultiEngineClient, хотя я использую IPython. Спасибо за управление!
  • 0
    Для меня неясно, могу ли я запустить ускоренный код с платформой параллельных вычислений IPython в режиме сценария, т.е. не работать через ipython.
Показать ещё 5 комментариев
26

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

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

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
  • 0
    Вы должны заменить output[ind] на output.flat[ind] чтобы код работал. ( output представляет собой двумерный массив, для которого потребуются два индекса.)
  • 0
    @Sven: Спасибо ... это происходит из-за постоянного переключения между matlab и python.
4

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

3

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. Вы должны создать функцию в рабочем каталоге (я назвал ее 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')

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

1

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

Чтобы распараллелить ваш пример, вам нужно определить свои функции с @ray.remote декоратора @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

Я перепробовал все решения здесь, но обнаружил, что самый простой способ и самый близкий эквивалент matlabs parfor - это шутка Нумбы.

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

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

Ещё вопросы

Сообщество Overcoder
Наверх
Меню