使用并行功能时的环境和范围

时间:2013-08-03 17:58:28

标签: r function parallel-processing scope

我有以下功能:

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

我猜这与我试图在函数内运行并行应用这一事实有关。你能帮帮我解决这个问题吗?感谢

2 个答案:

答案 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本身使用),但您必须知道自己在做什么,否则会严重影响您的性能,尤其是在使用时clusterApplyclusterApplyLB,因为他们不会parLapplyparCapply执行相同的预先安排

这是一个简单的例子,用于演示:

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”副本。

这似乎是一个学术问题,但是一旦你开始从函数内部调用parLapplyclusterApply等并行函数来执行未命名的worker函数,它就会以各种形式出现。我被这种问题多次咬过。