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

bde*_*vic 5 parallel-processing scope r 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...
}
Run Code Online (Sandbox Code Playgroud)

但我得到这个错误:

Error in get(name, envir = envir) : object 'iih_data' not found
Run Code Online (Sandbox Code Playgroud)

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

Ste*_*ton 7

正如您已经想到的那样,除非使用参数另有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()
Run Code Online (Sandbox Code Playgroud)

你认为你会得到一个错误,说'找不到'对象'iih_data',因为你没有明确地导出它,但你没有.奇怪的是,当从全局环境定义函数时,这不会发生,因为全局环境永远不会与函数一起序列化.

如果你认为这很奇怪,那么在处理参数时事情会变得陌生.考虑这个例子:

library(parallel)
cl <- makePSOCKcluster(3)
f1 <- function(iih_data) {
  parLapply(cl, 1:3, function(i) iih_data)
}
x <- 'foo'
f1(x)
Run Code Online (Sandbox Code Playgroud)

鉴于我之前的示例,您可能认为这会起作用,但您会收到以下错误:

Error in checkForRemoteErrors(val) : 
  3 nodes produced errors; first error: object 'x' not found
Run Code Online (Sandbox Code Playgroud)

但为什么它说"找不到对象'x'而不是找不到"对象'iih_data'?这是由于R对函数参数的惰性评估.该函数及其相关环境被序列化并发送给工作者,而无需评估参数"iih_data".在工作人员执行未命名的工作程序功能之前,不会对其进行评估,而且当发现工作人员的全局环境中未定义"x"时,就不会对其进行评估.

您可以通过更改f1为:

f1 <- function(iih_data) {
  force(iih_data)
  parLapply(cl, 1:3, function(i) iih_data)
}
Run Code Online (Sandbox Code Playgroud)

如果不是叫force你执行clusterExport(cl, 'iih_data', envir=environment()),它会起作用,但不是因为你已经将它导出给了工人.它会起作用,因为论证是强制性的,但效率要低得多,并且仍然不会使用复制到工人全局环境中的值.worker函数实际上仍然会使用本地环境中的"iih_data"副本,该副本是通过调用f1与未命名的worker函数一起序列化而创建的.

这似乎是一个学术问题,但它以各种形式,一旦你开始叫并行功能,如出现parLapply,并clusterApply从内部功能,以执行无名工人功能.我被这种问题多次咬了.


bde*_*vic 6

添加

envir=environment()
Run Code Online (Sandbox Code Playgroud)

到clusterExport()修复了问题.例如

clusterExport(cl, c("iih_data"),envir=environment())
Run Code Online (Sandbox Code Playgroud)