2013-08-03 17 views
13

Sto provando a eseguire un ciclo foreach su un server Windows con una CPU 16 core e 64 GB di RAM utilizzando RStudio. (utilizzando il pacchetto doParallel)lettura variabili globali utilizzando foreach in R

I processi "worker" copiano tutte le variabili dall'esterno del ciclo for (osservato osservando l'istanza di questi processi nel task manager di Windows quando viene eseguito il ciclo foreach), gonfiando così il memoria utilizzata da ogni processo. Ho cercato di dichiarare alcune delle variabili particolarmente grandi come globali, assicurandomi che anche queste variabili venissero lette e non scritte all'interno del ciclo foreach per evitare conflitti. Tuttavia, i processi utilizzano ancora rapidamente tutta la memoria disponibile.

Esiste un meccanismo per garantire che i processi "di lavoro" non creino copie di alcune variabili "di sola lettura"? Come un modo specifico per dichiarare tali variabili?

+0

Ho praticamente fatto la stessa domanda qualche tempo fa (http://stackoverflow.com/questions/6251662/writing-to-global-environment-when-running-in-parallel), ma le cose potrebbero essere cambiate nel mezzo tempo? –

+0

Grazie Roman, sono bloccato anche su Windows; si spera che qualcuno conosca una via d'uscita. Non ho bisogno di eseguire il polling/modificare la variabile grande (una rete) perché la leggo solo per calcolare i punteggi di centralità. – user2272413

+1

A seconda che i dati che si desidera condividere possano essere rappresentati da una matrice, il pacchetto 'bigmemory' potrebbe abilitare ciò che stai cercando. Questo pacchetto consente l'accesso condiviso per l'elaborazione parallela, anche su Windows. Tuttavia, se l'oggetto da condividere non può essere rappresentato da una matrice, non andrai lontano su quella strada. – BenBarnes

risposta

14

Il pacchetto doParallel esegue l'esportazione automatica delle variabili per gli operatori a cui viene fatto riferimento nel ciclo foreach. Se non vuoi farlo, puoi usare l'opzione ".noexport" foreach per impedirgli di esportare automaticamente determinate variabili. Ma se ti capisco bene, il tuo problema è che R sta successivamente duplicando alcune di quelle variabili, il che è ancora più problematico del solito dato che sta accadendo in più processi su una singola macchina.

Non esiste un modo per dichiarare una variabile in modo che R non ne faccia mai un duplicato. È necessario sostituire le variabili di problema con oggetti da un pacchetto come bigmemory in modo che le copie non vengano mai eseguite, oppure provare a modificare il codice in modo da non attivare la duplicazione. Puoi usare la funzione tracemem per aiutarti, poiché stamperà un messaggio ogni volta che quell'oggetto viene duplicato.

Tuttavia, è possibile evitare il problema riducendo i dati necessari agli operatori. Ciò riduce la quantità di dati che devono essere copiati su ciascuno dei lavoratori, oltre a ridurre il loro impatto sulla memoria.

Ecco un classico esempio di dare i lavoratori più dati di quelli di cui hanno bisogno:

x <- matrix(1:100, 10) 
foreach(i=1:10, .combine='c') %dopar% { 
    mean(x[,i]) 
} 

Poiché la matrice x viene fatto riferimento nel ciclo foreach, sarà auto-esportato a ciascuno dei lavoratori, anche anche se ogni lavoratore ha bisogno solo di un sottoinsieme delle colonne. La soluzione più semplice è per scorrere le colonne effettive della matrice anziché su indici colonna:

foreach(xc=x, .combine='c') %dopar% { 
    mean(xc) 
} 

Non solo è meno dati trasferiti ai lavoratori, ma ciascuno dei lavoratori in realtà solo bisogno di avere una colonna in memoria alla volta, che riduce notevolmente il suo ingombro di memoria per le matrici di grandi dimensioni. Il vettore xc può ancora finire per essere duplicato, ma non fa male quasi tanto perché è molto più piccolo di x.

Si noti che questa tecnica aiuta solo quando doParallel utilizza le funzioni "di neve derivata", come ad esempio parLapply e clusterApplyLB, non quando si utilizza mclapply. L'utilizzo di questa tecnica può rendere il ciclo un po 'più lento quando si utilizza mclapply, poiché tutti i lavoratori ottengono la matrice x gratuitamente, quindi perché trasferire attorno alle colonne quando i lavoratori hanno già l'intera matrice? Tuttavia, su Windows, doParallel non può utilizzare mclapply, quindi questa tecnica è molto importante.

L'importante è pensare a quali dati sono realmente necessari ai lavoratori per svolgere il proprio lavoro e cercare di ridurlo se possibile. A volte è possibile farlo utilizzando iteratori speciali, dai pacchetti iterators o itertools, ma è possibile farlo anche modificando l'algoritmo.