【发布时间】:2011-02-15 17:56:08
【问题描述】:
我正在尝试比较并行化选项。具体来说,我将标准的SNOW 和mulitcore 实现与使用doSNOW 或doMC 和foreach 的实现进行比较。作为一个样本问题,我通过多次计算从标准正态分布中抽取的样本均值来说明中心极限定理。这是标准代码:
CltSim <- function(nSims=1000, size=100, mu=0, sigma=1){
sapply(1:nSims, function(x){
mean(rnorm(n=size, mean=mu, sd=sigma))
})
}
这是SNOW 的实现:
library(snow)
cl <- makeCluster(2)
ParCltSim <- function(cluster, nSims=1000, size=100, mu=0, sigma=1){
parSapply(cluster, 1:nSims, function(x){
mean(rnorm(n=size, mean=mu, sd=sigma))
})
}
接下来,doSNOW 方法:
library(foreach)
library(doSNOW)
registerDoSNOW(cl)
FECltSim <- function(nSims=1000, size=100, mu=0, sigma=1) {
x <- numeric(nSims)
foreach(i=1:nSims, .combine=cbind) %dopar% {
x[i] <- mean(rnorm(n=size, mean=mu, sd=sigma))
}
}
我得到以下结果:
> system.time(CltSim(nSims=10000, size=100))
user system elapsed
0.476 0.008 0.484
> system.time(ParCltSim(cluster=cl, nSims=10000, size=100))
user system elapsed
0.028 0.004 0.375
> system.time(FECltSim(nSims=10000, size=100))
user system elapsed
8.865 0.408 11.309
SNOW 实现相对于无与伦比的运行节省了大约 23% 的计算时间(正如我们所预期的那样,随着模拟数量的增加,节省的时间会越来越多)。 foreach 尝试实际上增加运行时间 20 倍。此外,如果我将 %dopar% 更改为 %do% 并检查循环的非并行版本,它需要 7 秒以上。
另外,我们可以考虑multicore 包。为multicore 编写的模拟是
library(multicore)
MCCltSim <- function(nSims=1000, size=100, mu=0, sigma=1){
unlist(mclapply(1:nSims, function(x){
mean(rnorm(n=size, mean=mu, sd=sigma))
}))
}
我们获得了比SNOW 更好的速度提升:
> system.time(MCCltSim(nSims=10000, size=100))
user system elapsed
0.924 0.032 0.307
开始一个新的R会话,我们可以尝试使用doMC而不是doSNOW来实现foreach,调用
library(doMC)
registerDoMC()
然后像上面一样运行FECltSim(),仍然找到
> system.time(FECltSim(nSims=10000, size=100))
user system elapsed
6.800 0.024 6.887
这“仅”比非并行运行时增加了 14 倍。
结论:我的foreach 代码在doSNOW 或doMC 下都没有高效运行。知道为什么吗?
谢谢, 查理
【问题讨论】:
标签: r foreach parallel-processing