2013-07-07 28 views
7

Sto cercando di utilizzare un paio di cicli foreach in R per compilare un array comune in parallelo. Una versione molto semplificata di quello che sto cercando di fare è:cicli foreach nidificati in R per aggiornare l'array comune

library(foreach) 
set.seed(123) 
x <- matrix(NA, nrow = 8, ncol = 2) 

foreach(i=1:8) %dopar% { 
    foreach(j=1:2) %do% { 

     l <- runif(1, i, 100) 
     x[i,j] <- i + j + l  #This is much more complicated in my real code. 

    } 
} 

Vorrei codice per aggiornare la matrice x in parallelo e hanno l'aspetto di uscita come:

> x 
     [,1]  [,2] 
[1,] 31.47017 82.04221 
[2,] 45.07974 92.53571 
[3,] 98.22533 12.41898 
[4,] 59.69813 95.67223 
[5,] 63.38633 55.37840 
[6,] 102.94233 56.61341 
[7,] 78.01407 69.25491 
[8,] 26.46907 100.78390 

Tuttavia, non posso sembra capire come ottenere l'array per essere aggiornato. Ho provato a mettere il x <- altrove, ma non sembra piacergli. Penso che sarà una cosa molto semplice da risolvere, ma tutte le mie ricerche non mi hanno ancora condotto. Grazie.

+1

Ciao, solo un consiglio generale: se si utilizza un pacchetto specifico, è utile indicarlo nel codice di esempio. (Ho modificato il tuo codice per riflettere) –

+0

Grazie a @RicardoSaporta Ho dimenticato di farlo quando ho fatto l'esempio piccolo – joshdr83

risposta

11

foreach I loop vengono utilizzati per il loro valore di ritorno, come lapply. In questo modo sono molto diversi dai loop for che vengono utilizzati per i loro effetti collaterali. In base alle opportune .combine funzioni, l'interno foreach loop può restituire vettori che vengono combinati fila-wise in una matrice da parte esterna foreach ciclo:

x <- foreach(i=1:8, .combine='rbind') %dopar% { 
    foreach(j=1:2, .combine='c') %do% { 
    l <- runif(1, i, 100) 
    i + j + l 
    } 
} 

È anche possibile utilizzare l'operatore nesting: %:%:

x <- foreach(i=1:8, .combine='rbind') %:% 
    foreach(j=1:2, .combine='c') %dopar% { 
    l <- runif(1, i, 100) 
    i + j + l 
    } 

Si noti che set.seed probabilmente non farà ciò che si desidera, poiché viene eseguito sulla macchina locale, mentre i numeri casuali vengono generati in diverse sessioni R, possibilmente su macchine diverse.

+0

non lo sapevo riguardo a 'set.seed' - grazie per averlo indicato –

+0

Un buon punto sul seeding! – cryo111

+0

Fantastico, grazie ragazzi! – joshdr83

2

Solo per aggiungere qualcosa alla risposta di Steve: Penso che il punto cruciale sia che il back-end parallelo avvia più processi Rscript.exe (come si può vedere nel task manager). Alcuni oggetti utilizzati all'interno di foreach, ad esempio nel proprio caso , sono quindi copiati nella memoria allocata per ciascuno di questi processi. Non sono sicuro di come viene gestita la copia nel pacchetto , ma con le funzioni *ply del pacchetto plyr devi indicare esplicitamente gli oggetti che devono essere copiati. I diversi processi non condividono la loro memoria. (Io non sono a conoscenza di altri pacchetti R che possono utilizzare la memoria condivisa ...)

Si può dimostrare che la matrice x è in realtà copiato usando .Internal(inspect(x)) per stampare oggetti x s' posizione di memoria.

library(foreach) 
library(doParallel) 

x <- matrix(1:16, nrow = 8, ncol = 2) 
#print memory location of x 
capture.output(.Internal(inspect(x)))[1] 

#create parallel backend; in our case two Rscript.exe processes 
workers=makeCluster(2) 
registerDoParallel(workers) 

y<- foreach(i=1:8, .combine='rbind') %dopar% { 
    #return memory location of x 
    capture.output(.Internal(inspect(x)))[1] 
} 

#print matrix y 
#there should be two different memory locations - 
#according to the two Rscript.exe processes started above 
y 

#close parallel backend 
stopCluster(workers) 

La matrice y legge

 [,1]                   
result.1 "@0x0000000003dab910 13 INTSXP g0c5 [NAM(1),ATT] (len=16, tl=0) 1,2,3,4,5,..." 
result.2 "@0x0000000003dab9b0 13 INTSXP g0c5 [NAM(1),ATT] (len=16, tl=0) 1,2,3,4,5,..." 
result.3 "@0x0000000003dab910 13 INTSXP g0c5 [NAM(2),ATT] (len=16, tl=0) 1,2,3,4,5,..." 
result.4 "@0x0000000003dab910 13 INTSXP g0c5 [NAM(2),ATT] (len=16, tl=0) 1,2,3,4,5,..." 
... 

Si dovrebbe trovare due diversi indirizzi di memoria lì.

Problemi correlati