我正在尝试弄清楚如何将函数和包传递给boot()
运行并行计算时的函数。在循环内加载包或定义函数似乎非常昂贵。这foreach()
我经常用于其他并行任务的函数有一个 .packages 和 .export 参数来处理这个问题(请参阅此所以问题 https://stackoverflow.com/questions/4765256/could-not-find-function-inside-foreach-loop)以一种很好的方式,但我不知道如何使用引导包来做到这一点。
下面是一个毫无意义的例子,展示了切换到并行时会发生什么:
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 倍。我想这一定是列表合并的结果,因为我找不到任何其他解释。