I'm looking to use parLapply()
on windows within an R6
object and noticed (that in at least some cases) that I do not need to export the R6 functions or data to the nodes.
Here is an example where I can access private methods within 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
And a second example where I can also access public members:
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
My question is twofold: (1) What about R6 makes this possible so that I don't need to export data objects and functions; and (2) can I rely on this behavior or is this an artifact of these specific examples?
UPDATE:
This behavior also appears to work using public methods and members after the object has been instantiated:
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
With R6 classes, every time you instantiate an object, that object gets a copy of each function/method, with a modified environment. The functions are assigned an environment where self
points to the object's public environment (this is the public face of the object), and private
points to the object's private environment.
This is different from S3 methods, which don't get copied for each instantiation of an object.
In summary: with R6, everything is self-contained in the object; with S3, the object does not contain methods.
I'm not that familiar with using parLapply
, but I think that it's safe to rely on things working like that with parLapply
.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With