我有以下功能:
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...
}
但是我收到了这个错误:
Error in get(name, envir = envir) : object 'iih_data' not found
我猜这与我试图在函数内运行并行应用这一事实有关。你能帮帮我解决这个问题吗?感谢
答案 0 :(得分:6)
添加
envir=environment()
到clusterExport()修复了问题。 e.g。
clusterExport(cl, c("iih_data"),envir=environment())
答案 1 :(得分:6)
正如您所知,clusterExport
在.GlobalEnv
中查找指定的变量,除非使用envir
参数另有指示。但是在您的特定示例中,iih_data
与您使用parCapply
执行的未命名函数一起被序列化,因此您通过clusterExport
导出到工作人员的副本赢了“实际上是用的。实际上,执行f1
之前parCapply
中定义的所有局部变量将与未命名的worker函数一起序列化并发送给每个worker。
此技术对于向工作人员发送数据非常有用(它实际上由clusterExport
本身使用),但您必须知道自己在做什么,否则会严重影响您的性能,尤其是在使用时clusterApply
和clusterApplyLB
,因为他们不会parLapply
和parCapply
执行相同的预先安排。
这是一个简单的例子,用于演示:
library(parallel)
cl <- makePSOCKcluster(3)
f1 <- function() {
iih_data <- 'foo'
parLapply(cl, 1:3, function(i) iih_data)
}
f1()
你认为你会得到一个错误,说“找不到对象'iih_data'”,因为你没有明确地导出它,但你没有。奇怪的是,当从全局环境定义函数时,这不会发生,因为全局环境永远不会与函数一起序列化。
如果你觉得这很奇怪,那么在处理争论时,事情会变得陌生。考虑这个例子:
library(parallel)
cl <- makePSOCKcluster(3)
f1 <- function(iih_data) {
parLapply(cl, 1:3, function(i) iih_data)
}
x <- 'foo'
f1(x)
鉴于我之前的示例,您可能认为这会起作用,但您会收到以下错误:
Error in checkForRemoteErrors(val) :
3 nodes produced errors; first error: object 'x' not found
但为什么它说“找不到对象'x'而不是找不到”对象'iih_data'?这是由于R对函数参数的惰性评估。该函数及其相关环境被序列化并发送给工作者,而无需评估参数“iih_data”。在工人执行未命名的工作函数之前,它不会被评估,而且当它发现在工作者的全局环境中没有定义“x”时。
您可以通过将f1
更改为:
f1 <- function(iih_data) {
force(iih_data)
parLapply(cl, 1:3, function(i) iih_data)
}
如果您执行force
而不是调用clusterExport(cl, 'iih_data', envir=environment())
,它会起作用,但不是因为您已将其导出给工作人员。它会起作用,因为论证是强制性的,但效率要低得多,并且仍然不会使用复制到工人全局环境中的值。 worker函数仍然实际使用通过调用与未命名的worker函数一起序列化的f1
创建的本地环境中的“iih_data”副本。
这似乎是一个学术问题,但是一旦你开始从函数内部调用parLapply
和clusterApply
等并行函数来执行未命名的worker函数,它就会以各种形式出现。我被这种问题多次咬过。