2011-01-13 7 views
35

Sto cercando una risposta definitiva al parfor di MATLAB per Python (Scipy, Numpy).Parfor per Python

Esiste una soluzione simile a parfor? In caso contrario, qual è la complicazione per crearne uno?

UPDATE: Ecco un tipico codice di calcolo numerico che ho bisogno di accelerare

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) 

Un esempio di una funzione di calcolo pesante è:

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] 

risposta

16

Ci sono molti Python frameworks for parallel computing. Quello che mi piace di più è IPython, ma non ne so molto di nessuno degli altri. In IPython, un analogo a parfor sarebbe client.MultiEngineClient.map() o alcuni degli altri costrutti in the documentation on quick and easy parallelism.

+1

+1 non sapeva di client.MultiEngineClient anche se io uso IPython. Grazie per il manzo! –

+0

Non è chiaro per me se posso eseguire un codice accelerato con il framework di calcolo parallelo IPython in modalità di script, cioè non eseguendo ipython. –

+0

@Dat Chu: Certo che puoi. Basta scrivere i comandi che dovresti digitare al prompt in un file ed eseguirlo con Python. (È questo che stai chiedendo?) –

3

ho sempre usato Parallel Python ma non è un analogo completo poiché credo che in genere utilizzi processi separati che possono essere costosi su determinati sistemi operativi. Tuttavia, se il corpo dei vostri anelli è abbastanza grosso allora questo non importa e può effettivamente avere alcuni benefici.

25

Quello integrato in python sarebbe multiprocessing documenti sono here. Io uso sempre lo multiprocessing.Pool con altrettanti addetti ai processori. Quindi ogni volta che ho bisogno di fare una struttura simile al ciclo io uso Pool.imap

Fintanto che il corpo della tua funzione non dipende da alcuna iterazione precedente, allora dovresti avere una velocità quasi lineare. Ciò richiede anche che gli input e gli output siano pickle -able ma questo è abbastanza semplice da garantire per i tipi standard.

UPDATE: del codice per la funzione aggiornata solo per mostrare quanto sia facile:

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

Dovresti sostituire 'output [ind]' con 'output.flat [ind]' per far funzionare il codice. ('output' è una matrice bidimensionale e avrebbe bisogno di due indici.) –

+0

@Sven: Grazie ... che deriva dal passaggio tra matlab e python tutto il tempo. – JudoWill

2

Jupyter Notebook

Per vedere un esempio considera che si desidera scrivere l'equivalenza di questo codice Matlab su in 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') 

Il modo in cui si può scrivere questo in python in particolare nel taccuino jupyter. È necessario creare una funzione nella directory di lavoro (ho chiamato FunForParFor.py) che ha il seguente

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

Poi vado al mio notebook Jupyter e scrivere il seguente codice

import multiprocessing 
import FunForParFor 

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

Questo ha ha funzionato per me! Volevo solo condividerlo qui per darti un esempio particolare.