foreach并行化问题
我试图比较并行化选项。具体来说,我将标准的foreach并行化问题,r,foreach,parallel-processing,R,Foreach,Parallel Processing,我试图比较并行化选项。具体来说,我将标准的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
和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))
})
}
接下来,使用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))
}
}
相对于非并行运行,SNOW
实现节省了约23%的计算时间(正如我们所预期的,随着模拟次数的增加,节省的时间会越来越多)。foreach
尝试实际上将运行时间增加了20倍。此外,如果我将%dopar%
更改为%do%
,并检查循环的未配置版本,则需要7秒以上的时间
另外,我们可以考虑<代码>多核< /代码>包。为
多核
编写的模拟是
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))
}))
}
启动新的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
下都不能有效运行。知道为什么吗
谢谢,
Charlie首先,您可以编写更简洁的foreach代码:
FECltSim <- function(nSims=1000, size=100, mu=0, sigma=1) {
foreach(i=1:nSims, .combine=c) %dopar% {
mean(rnorm(n=size, mean=mu, sd=sigma))
}
}
超过40%的时间它都在忙着挑选东西。它还为整个操作使用了许多其他功能。实际上,foreach
只有在通过非常耗时的函数进行的回合数相对较少的情况下才是可取的
另外两个解决方案基于不同的技术,在R中的作用要小得多。在一个侧节点上,
snow
实际上最初开发用于集群而不是单个工作站,如multi-core
is。接下来是Joris所说的,foreach()
当作业数量不超过您将使用的处理器数量时,这是最好的选择。或者更一般地说,当每项作业本身花费大量时间(比如秒或分钟)时。在创建线程时会有很多开销,所以你真的不想在很多小作业中使用它。如果您正在进行1000万模拟人生而不是1万模拟人生,并且您的代码结构如下:
nSims = 1e7
nBatch = 1e6
foreach(i=1:(nSims/nBatch), .combine=c) %dopar% {
replicate(nBatch, mean(rnorm(n=size, mean=mu, sd=sigma))
}
我打赌你会发现foreach做得很好
还请注意,对于此类应用程序,使用了
replicate()
,而不是sapply。实际上,foreach
包有一个类似的便利函数,times()
,可以应用于这种情况。当然,如果您的代码不是每次都使用相同的参数进行简单的模拟,那么您需要sapply()
和foreach()
再次感谢Jons。实际上,我以前没有使用过Rprof,您能解释一下如何解释这个输出,或者给我指出一个可以解释的资源吗?我查看了R的本机帮助文件以获取summaryRprof
,但没有那么大帮助。@Charlie:self.time是函数本身花费的时间。self.pct是函数本身花费的总时间的百分比。total.time是在该函数或其调用的任何其他函数中花费的时间。例:f1谢谢。$
,$我检查了帮助文件(summaryRprof
和Rprof
),但他们没有讨论解释。@Charlie:我指的是.Call、“$”等帮助文件。谢谢你建议将流程分成批处理;我敢打赌,这会节省不少沟通时间。我以前看过复制
,但没有看过次
。
> system.time(FECltSim(nSims=10000, size=100))
user system elapsed
6.800 0.024 6.887
FECltSim <- function(nSims=1000, size=100, mu=0, sigma=1) {
foreach(i=1:nSims, .combine=c) %dopar% {
mean(rnorm(n=size, mean=mu, sd=sigma))
}
}
$by.self
self.time self.pct total.time total.pct
$ 5.46 41.30 5.46 41.30
$<- 0.76 5.75 0.76 5.75
.Call 0.76 5.75 0.76 5.75
...
nSims = 1e7
nBatch = 1e6
foreach(i=1:(nSims/nBatch), .combine=c) %dopar% {
replicate(nBatch, mean(rnorm(n=size, mean=mu, sd=sigma))
}