I have the following function:
f1<-function(x){
iih_data<-...stuff...
...more stuff...
cl <- makeCluster(mc <- getOption("cl.cores", 6))
clusterExport(cl, c("iih_data"))
clusterEvalQ(cl, require(lme4))
Tstar<-parCapply(cl, ystar, function(x){
ostar=glmer(x ~ GENO + RACE + (1|GROUP), family="binomial",data=iih_data,nAGQ=1)
fixef(ostar)[2]/sqrt(vcov(ostar)[2,2])
})
stopCluster(cl)
...more stuff...
}
But I get this error:
Error in get(name, envir = envir) : object 'iih_data' not found
I am guessing it has to do with the fact that I am trying to run parallel apply inside of a function. Can you guys help me sort this out? Thanks
mclapply is a parallelized version of lapply , it returns a list of the same length as X , each element of which is the result of applying FUN to the corresponding element of X . It relies on forking and hence is not available on Windows unless mc. cores = 1 .
Parallel processing (in the extreme) means that all the f# processes start simultaneously and run to completion on their own. If we have a single computer at our disposal and have to run n models, each taking s seconds, the total running time will be n*s .
There are various packages in R which allow parallelization. “parallel” Package The parallel package in R can perform tasks in parallel by providing the ability to allocate cores to R. The working involves finding the number of cores in the system and allocating all of them or a subset to make a cluster.
As you've figured out, clusterExport
looks for the specified variables in .GlobalEnv
unless directed otherwise with the envir
argument. But in your particular example, iih_data
is being serialized along with the unnamed function that you're executing with parCapply
, so the copy that you're exporting to the workers via clusterExport
won't actually be used. In fact, all of the local variables that are defined in f1
before parCapply
is executed will be serialized along with the unnamed worker function and sent to each of the workers.
This technique can be very useful for sending data to the workers (it's actually used by clusterExport
itself), but you have to know what you're doing, otherwise it can significantly hurt your performance, especially when using clusterApply
and clusterApplyLB
, since they don't do the same prescheduling done by parLapply
and parCapply
.
Here's a simple example that demonstrates this:
library(parallel)
cl <- makePSOCKcluster(3)
f1 <- function() {
iih_data <- 'foo'
parLapply(cl, 1:3, function(i) iih_data)
}
f1()
You'd think that you would get an error saying "object 'iih_data' is not found" since you haven't explicitly exported it, but you don't. The odd thing is that this doesn't happen when the function is defined from the global environment, because the global environment is never serialized along with functions.
If you think that's strange, things get stranger when dealing with arguments. Consider this example:
library(parallel)
cl <- makePSOCKcluster(3)
f1 <- function(iih_data) {
parLapply(cl, 1:3, function(i) iih_data)
}
x <- 'foo'
f1(x)
Given my previous example, you might think that this would work, but instead you get the following error:
Error in checkForRemoteErrors(val) :
3 nodes produced errors; first error: object 'x' not found
But why does it say "object 'x' not found" rather than "object 'iih_data' not found"? This is due to R's lazy evaluation of function arguments. The function and its associated environment is serialized and sent to the workers without ever evaluating the argument "iih_data". It's not evaluated until the unnamed worker function is executed on the workers, and that's when it discovers that "x" is not defined in the global environment of the workers.
You can fix this by changing f1
to:
f1 <- function(iih_data) {
force(iih_data)
parLapply(cl, 1:3, function(i) iih_data)
}
If instead of calling force
you executed clusterExport(cl, 'iih_data', envir=environment())
, it would work, but not because you've exported it to the workers. It would work because the argument had been forced, but in a much less efficient way, and the values copied to the global environment of the workers would still not be used. The worker function would still actually use the copy of "iih_data" that was in the local environment that was created by calling f1
that was serialized along with the unnamed worker function.
This may seem like an academic issue, but it comes up in various forms once you start to call parallel functions such as parLapply
and clusterApply
from inside functions in order to execute unnamed worker functions. I've been bitten many times by this kind of problem.
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