在函数内部调用 clusterApply 时,性能会下降

mri*_*rip 5 parallel-processing 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))
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 
Run Code Online (Sandbox Code Playgroud)

现在,为了确保没有发生任何奇怪的情况,请重新启动 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 
Run Code Online (Sandbox Code Playgroud)

我做了一些搜索,找到了相关问题的答案,它指出未在全局环境中定义的函数中使用的局部变量将导出到集群。所以我想,也许问题在于x导出了两次,这才是花费很长时间的原因,而不是实际的函数调用。为了测试这一点,我将函数定义更改为:

f0<-function(z) eigen(get("x")[[z]])
Run Code Online (Sandbox Code Playgroud)

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

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

clusterApply(clust,x,eigen)
Run Code Online (Sandbox Code Playgroud)

在函数内部,那么它就可以正常工作,就像在全局环境中一样快。当然,如果这是我想要解决的问题,我会简单地这样做,但事实并非如此,这只是一个玩具问题,用于隔离我与其他更复杂的代码遇到的问题。

Ste*_*ton 6

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

如果你想f0在 inside定义,你可以通过修改定义后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)))
}
Run Code Online (Sandbox Code Playgroud)

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

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