2016-01-14 18 views
10

Sto cercando di utilizzare parLapply() su Windows all'interno di un oggetto R6 e ho notato (che in alcuni casi almeno) che non è necessario esportare le funzioni o i dati R6 ai nodi.parLapply all'interno delle classi R6

Ecco un esempio in cui posso accedere ai metodi privati ​​entro parLapply():

require(R6);require(parallel) 
square <- 
R6Class("square", 
     public = list(
      numbers = NA, 
      squares = NA, 
      initialize = function(numbers,integer) { 
       self$numbers <- numbers 
       squares <- private$square.numbers() 
      } 
     ), 
     private = list(
      square = function(x) { 
       return(x^2) 
      }, 
      square.numbers = function() { 
       cl <- makeCluster(detectCores()) 
       self$squares <- parLapply(cl, 
              self$numbers, 
              function (x) private$square(x) 
             ) 
       stopCluster(cl) 
      } 
     )) 
##Test 
test <- square$new(list(1,2,3)) 
print(test$squares) 
# [[1]] 
# [1] 1 
# 
# [[2]] 
# [1] 4 
# 
# [[3]] 
# [1] 9 

E un secondo esempio in cui posso anche accedere ai membri pubblici:

square2 <- 
R6Class("square2", 
     public = list(
      numbers = NA, 
      squares = NA, 
      integer = NA, 
      initialize = function(numbers,integer) { 
       self$numbers <- numbers 
       self$integer <- integer 
       squares <- private$square.numbers() 
      } 
     ), 
     private = list(
      square = function(x) { 
       return(x^2) 
      }, 
      square.numbers = function() { 
       cl <- makeCluster(detectCores()) 
       self$squares <- parLapply(cl, 
              self$numbers, 
              function (x) private$square(x)+self$integer 
             ) 
       stopCluster(cl) 
      } 
     )) 
##Test 
test2 <- square2$new(list(1,2,3),2) 
print(test2$squares) 
#[[1]] 
#[1] 3 
# 
#[[2]] 
#[1] 6 
# 
#[[3]] 
#[1] 11 

La mia domanda è duplice: (1) Per quanto riguarda R6, ciò è possibile in modo che non sia necessario esportare oggetti e funzioni dati; e (2) posso fare affidamento su questo comportamento o è un artefatto di questi esempi specifici?

UPDATE:

Questo comportamento appare anche a lavorare con metodi pubblici e membri dopo che l'oggetto è stato istanziato:

square3 <- R6Class(
    classname = "square3", 
    public = list(
     numbers = NA, 
     squares = NA, 
     integer = NA, 
     square = function(x) { 
      return(x^2) 
     }, 
     square.numbers = function() { 
      cl <- makeCluster(detectCores()) 
      self$squares <- parLapply(cl, 
             self$numbers, 
            function (x) self$square(x)+self$integer 
           ) 
     stopCluster(cl) 
    }, 
    initialize = function(numbers,integer) { 
     self$numbers <- numbers 
     self$integer <- integer 
    } 
    ) 
) 
test3.obj <- square3$new(list(1,2,3),2) 
test3.obj$square.numbers() 
test3.obj$squares 

# [[1]] 
# [1] 3 
# 
# [[2]] 
# [1] 6 
# 
# [[3]] 
# [1] 11 

risposta

1

Con le classi R6, ogni volta che si crea un'istanza di un oggetto, l'oggetto ottiene una copia di ogni funzione/metodo, con un ambiente modificato. Alle funzioni viene assegnato un ambiente in cui self punta all'ambiente pubblico dell'oggetto (questa è la faccia pubblica dell'oggetto) e private punti all'ambiente privato dell'oggetto.

Questo è diverso dai metodi S3, che non vengono copiati per ogni istanza di un oggetto.

In sintesi: con R6, tutto è autonomo nell'oggetto; con S3, l'oggetto non contiene metodi.

Non ho familiarità con l'utilizzo di parLapply, ma penso che sia sicuro fare affidamento su cose che funzionano in questo modo con parLapply.

+0

grazie! questo è un grande aiuto – chandler

+0

Sono un po 'perplesso da questa spiegazione: non dovrebbe funzionare lo stesso anche con S3, semplicemente perché ogni fork di R ottiene la propria copia del working set (il kernel del sistema operativo gestisce questo, non R) ? Ad ogni modo, ho sempre usato 'mclapply' come questo (non uso' parLapply' o cluster espliciti), non ho mai dovuto esportare nulla. –

+0

Sembra che tu stia lavorando su os x/linux. Dalla mia (limitata) comprensione, su questi sistemi operativi il "fork" ottiene l'intera directory di lavoro, cosa che non succede su Windows. Ecco perché ero così curioso di questo comportamento in quanto non ci richiederebbe agli utenti di Windows di esportare metodi o membri (e quindi rendere l'implementazione parallela molto più comoda). Inoltre, non ho lavorato molto con s3, quindi non posso commentare il suo comportamento in una situazione simile – chandler