当在函数内部调用时,clusterApply的性能会恶化

时间:2013-10-19 14:28:25

标签: r parallel-processing

我遇到了一个clusterApply的奇怪问题,我已经能够尽可能地将其隔离出来,如下所示。首先,我从全球环境中运行以下代码:

require(parallel)
cl<-makeCluster(rep("localhost",20),"SOCK")
xl<-list()
for(i in 1:20)
  xl[[i]]<-crossprod(matrix(rnorm(1e6),1000,1000))
x<-xl
clusterExport(cl,"x",environment())
f0<-function(z) eigen(x[[z]])
system.time(clusterApply(cl,1:20,f0))
##    user  system elapsed 
##   0.332   0.264   3.334 

现在,为了确保没有任何奇怪的事情发生,重新启动R,现在运行类似的代码,从函数内部调用clusterApply

require(parallel)
cl<-makeCluster(rep("localhost",20),"SOCK")
xl<-list()
for(i in 1:20)
  xl[[i]]<-crossprod(matrix(rnorm(1e6),1000,1000))
f<-function(clust,x){
  force(x)
  clusterExport(clust,"x",environment())
  f0<-function(z) eigen(x[[z]])
  print(system.time(clusterApply(clust,1:20,f0)))
}
f(cl,xl)
##   user  system elapsed 
##  5.212   1.888  13.627 

我做了一些搜索并找到this answer to a related question,它指出在全局环境中未定义的函数中使用的局部变量将导出到集群。所以我想,也许问题是x导出两次,这就是需要很长时间,而不是实际的函数调用。为了测试这个,我将函数定义更改为:

f0<-function(z) eigen(get("x")[[z]])

我仍然表现得很慢。有谁知道这里会发生什么?

顺便说一句,如果我只是打电话

clusterApply(clust,x,eigen)

在函数内部,它运行正常,就像它在全局环境中一样快。当然,如果这是我试图解决的问题,我只是这样做,但事实并非如此,这只是一个玩具问题,将我遇到的问题与其他更复杂的代码隔离开来。

1 个答案:

答案 0 :(得分:3)

您的表现确实受到了影响,因为变量x与每个任务中的f0函数一起发送。更改f0引用x的方式没有任何区别:问题与f0使用x的方式或是否引用x无关所有。它与定义f0本身的位置有关。如果您在f之外定义它以使f0的关联环境是全局环境,那么您的问题将得到解决。

如果您想在f0内定义f,可以在定义后修改f0的环境来修复它:

f<-function(clust,x){
  force(x)
  clusterExport(clust,"x",environment())
  f0<-function(z) eigen(x[[z]])
  environment(f0) <- .GlobalEnv
  print(system.time(clusterApply(clust,1:20,f0)))
}

这解决了这个问题,因为全局环境永远不会与函数一起序列化。

clusterApply(clust,x,eigen)效果良好的原因是eigen未定义f,因此在x序列化时未捕获eigen