我正在尝试弄清楚如何在运行并行计算时将函数和包传递给
下面是一个无意义的示例,展示了切换到并行计算时会发生什么:
boot()
函数。在循环内部加载包或定义函数似乎非常昂贵。我经常使用的foreach()
函数有一个 .packages 和 .export 参数来处理这个问题(参见这个SO 问题),但我无法找到如何在boot包中实现这一点。下面是一个无意义的示例,展示了切换到并行计算时会发生什么:
library(boot)
myMean <- function(x) mean(x)
meaninglessTest <- function(x, i){
return(myMean(x[i]))
}
x <- runif(1000)
bootTest <- function(){
out <- boot(data=x, statistic=meaninglessTest, R=10000, parallel="snow", ncpus=4)
return(boot.ci(out, type="perc"))
}
bootTest()
根据预期,抱怨无法找到myMean
。
附注:运行此示例时,速度比单核慢,可能因为将这个简单的任务分成多个核比实际任务更耗时。为什么默认不将任务平均分配给R/ncpus
个工作批次,这个默认行为有什么原因吗?
关于附注的更新:正如Steve Weston所指出的,boot()使用的parLapply实际上将任务分成均匀的批次/块。该函数是clusterApply的一个很好的包装器:
docall(c, clusterApply(cl, splitList(x, length(cl)), lapply,
fun, ...))
当我增加重复次数时,我对这个表现不佳感到有些惊讶:
> library(boot)
> set.seed(10)
> x <- runif(1000)
>
> Reps <- 10^4
> start_time <- Sys.time()
> res <- boot(data=x, statistic=function(x, i) mean(x[i]),
+ R=Reps, parallel="no")
> Sys.time()-start_time
Time difference of 0.52335 secs
>
> start_time <- Sys.time()
> res <- boot(data=x, statistic=function(x, i) mean(x[i]),
+ R=Reps, parallel="snow", ncpus=4)
> Sys.time()-start_time
Time difference of 3.539357 secs
>
> Reps <- 10^5
> start_time <- Sys.time()
> res <- boot(data=x, statistic=function(x, i) mean(x[i]),
+ R=Reps, parallel="no")
> Sys.time()-start_time
Time difference of 5.749831 secs
>
> start_time <- Sys.time()
> res <- boot(data=x, statistic=function(x, i) mean(x[i]),
+ R=Reps, parallel="snow", ncpus=4)
> Sys.time()-start_time
Time difference of 23.06837 secs
我希望这只是由于非常简单的均值函数,更复杂的情况应该表现得更好。我必须承认,我觉得有点不安,因为集群初始化时间在10,000和100,000个案例中应该是相同的,然而绝对时间差异增加,4核版本需要5倍的时间。我猜这一定是列表合并的影响,因为我找不到其他解释。
boot
还允许您使用cl
参数指定一个簇。创建一个簇并以这种方式传递它对我很有效。这对您来说是一个选项吗? - BenBarnes