2015-08-19 12 views
12

Sto cercando di creare un pezzo di codice parallelo per accelerare l'elaborazione di un array molto grande (un paio di centinaia di milioni di righe). Per parallelizzare questo, ho tagliato i miei dati in 8 pezzi (il mio numero di core) e ho provato a mandare ogni lavoratore 1 pezzo. Guardando il mio utilizzo della RAM tuttavia, sembra ogni pezzo è inviare a ciascun lavoratore, moltiplicando in modo efficace il mio utilizzo di RAM per 8. Un esempio di lavoro minima:Invio di dati ai lavoratori

A = 1:16; 
for ii = 1:8 
    data{ii} = A(2*ii-1:2*ii); 
end 

Ora, quando trasmetto questi dati ai lavoratori utilizzando parfor sembra per inviare la cellula completo invece di appena il pezzo desiderato:

output = cell(1,8); 
parfor ii = 1:8 
    output{ii} = data{ii}; 
end 

io in realtà uso qualche funzione all'interno del ciclo parfor, ma questo illustra il caso. MATLAB invia effettivamente la cella intera data a ciascun lavoratore e, in tal caso, come farla inviare solo il pezzo desiderato?

+4

Se i dati sono un [variabile a fette] (http://mathworks.com/help/distcomp/sliced-variables.html) sarà "fette" e solo quelle fette verranno trasmesse ai lavoratori ; stai usando le variabili affettate nel tuo codice reale? –

+0

Sto usando un array di celle nel mio codice attuale, come presentato qui. Vedrò la funzione variabile a fette, grazie. – Adriaan

+0

Forse si affetta manualmente, inviando singoli lavori per ogni pezzo: http://de.mathworks.com/help/distcomp/submit.html – Daniel

risposta

10

Nella mia esperienza personale, ho trovato che usare parfeval è meglio per quanto riguarda l'utilizzo della memoria di parfor. Inoltre, il tuo problema sembra essere più fragile, quindi puoi usare parfeval per inviare lavori più piccoli ai lavoratori di MATLAB.

Supponiamo che tu abbia workerCnt lavoratori MATLAB a cui gestirai i lavori jobCnt. Sia data un array di celle di dimensioni jobCnt x 1 e ognuno dei suoi elementi corrisponde a un input di dati per la funzione getOutput che esegue l'analisi sui dati. I risultati vengono quindi memorizzati nell'array di celle output della dimensione jobCnt x 1.

nel seguente codice, i lavori vengono assegnati nel primo ciclo for ei risultati vengono recuperati nel secondo ciclo while. La variabile booleana doneJobs indica quale lavoro è stato eseguito.

poolObj = parpool(workerCnt); 
jobCnt = length(data); % number of jobs 
output = cell(jobCnt,1); 
for jobNo = 1:jobCnt 
    future(jobNo) = parfeval(poolObj,@getOutput,... 
     nargout('getOutput'),data{jobNo}); 
end 
doneJobs = false(jobCnt,1); 
while ~all(doneJobs) 
    [idx,result] = fetchnext(future); 
    output{idx} = result; 
    doneJobs(idx) = true; 
end 

Inoltre, è possibile adottare questo approccio un ulteriore passo avanti se si desidera risparmiare più memoria. Quello che potresti fare è che dopo aver recuperato i risultati di un lavoro svolto, puoi eliminare il membro corrispondente di future. Il motivo è che questo oggetto memorizza tutti i dati di input e output della funzione getOutput che probabilmente sarà enorme. Ma devi stare attento, eliminando i membri dello spostamento dell'indice dei risultati future.

Quanto segue è il codice che ho scritto per questo porpuse.

poolObj = parpool(workerCnt); 
jobCnt = length(data); % number of jobs 
output = cell(jobCnt,1); 
for jobNo = 1:jobCnt 
    future(jobNo) = parfeval(poolObj,@getOutput,... 
     nargout('getOutput'),data{jobNo}); 
end 
doneJobs = false(jobCnt,1); 
while ~all(doneJobs) 
    [idx,result] = fetchnext(future); 
    furure(idx) = []; % remove the done future object 
    oldIdx = 0; 
    % find the index offset and correct index accordingly 
    while oldIdx ~= idx 
     doneJobsInIdxRange = sum(doneJobs((oldIdx + 1):idx)); 
     oldIdx = idx 
     idx = idx + doneJobsInIdxRange; 
    end 
    output{idx} = result; 
    doneJobs(idx) = true; 
end 
3

Vorrei suggerire di utilizzare il comando spmd di MATLAB.

È possibile scrivere il codice quasi come sarebbe per un'implementazione non parallela e avere anche accesso al lavoratore corrente tramite la variabile "sistema" labindex.

Date un'occhiata qui:

http://www.mathworks.com/help/distcomp/spmd.html

E anche in questa domanda SO su spmd vs parfor:

SPMD vs. Parfor

+0

Anche se l'utilizzo di SPMD potrebbe aiutare il codice, elude la domanda anziché rispondere. Voglio sapere come inviare correttamente i miei dati ai lavoratori senza un sovraccarico ridicolo, quindi posso usarli anche in altri pezzi di codice. – Adriaan

+0

L'uso di spmd o parfor non ha importanza in termini di utilizzo della RAM, ma il codice che utilizza spmd richiede ~ 1,2 volte di più rispetto all'implementazione di parfor. – Adriaan

+0

Se si utilizza la stessa logica dell'esempio fornito, si ha qualcosa di sbagliato nel codice. Dal momento che richiederebbe quasi un debug del tuo codice per vedere l'errore effettivo, ti suggerisco una rapida alternativa per risolvere il tuo problema. Se si richiede specificamente parfor, è necessario inserire l'intero codice. – Xxxo

4

Il commento da @ms è corretta - quando parforfette un array, quindi ad ogni worker viene inviata solo la slice necessaria per l'iterazione del ciclo ns su cui sta lavorando. Tuttavia, potresti vedere l'aumento dell'utilizzo della RAM oltre a quello che ti aspetti in origine, poiché purtroppo sono richieste copie dei dati che vengono trasmesse dal client agli operatori tramite il meccanismo di comunicazione parfor.

Se i dati sono necessari solo per i lavoratori, la soluzione migliore è creare/caricare/accedervi solo sui lavoratori, se possibile. Sembra che tu stia cercando il parallelismo dei dati piuttosto che il parallelismo delle attività, per il quale lo standard spmd è davvero migliore (come suggerisce @ Kostas).

+0

In effetti, dopo il parallelismo dei dati, desidero applicare la stessa operazione a tutte le mie centinaia di milioni di righe. Tuttavia, non posso creare i miei dati sui lavoratori, poiché devo caricarli prima da un file esterno. Questi dati devono quindi essere ordinati e tagliati in pezzi e ogni pezzo inviato a un lavoratore. Quindi, dopo che ciascun operatore ha eseguito l'attività designata, desidero raccogliere l'array completo nel mio cliente, per continuare a lavorarci. – Adriaan

+0

Le pagine di dati sulle variabili affettate sono un po 'corte per i miei gusti, è possibile che si aggiunga una piccola porzione di codice che mostra come tagliare una variabile? Per esempio, l'array A oi dati della cella andranno bene. – Adriaan