我正在尝试使用doSMP package为foreach包提供并行后端。
你能指出我做错了什么吗?实际上,以这种方式使用foreach会大大增加计算时间......
#------register doSMP to be used with foreach------
library(doSMP)
w <- startWorkers(4)
registerDoSMP(w)
#--------------------------------------------------
#------A simple function------
sim <- function(a, b)
{
return(10 * a + b)
}
avec <- 1:200
bvec <- 1:400
#-----------------------------
#------The naive method------
ptime <- system.time({
mat <- matrix(NA, nrow=length(avec), ncol=length(bvec))
for(i in 1:length(avec))
{
for(j in 1:length(bvec))
{
mat[i, j] <- sim(avec[i], bvec[j])
}
}
})[3]
ptime
elapsed
0.36
#----------------------------
#------Using foreach------
ptime <- system.time({
mat2 <- foreach(b=bvec, .combine="cbind") %:%
foreach(a=avec, .combine="c") %dopar%
{
sim(a, b)
}
})[3]
ptime
elapsed
86.98
#-------------------------
修改
That question与此非常相似,已从stats.stackexchange迁移。
答案 0 :(得分:4)
我个人不喜欢doSMP包,因为它经常崩溃我的R.它是为REvolution构建而开发的,并且无法在我的机器上顺利运行。例如,上面的代码,未经修改,只会崩溃我的R.
接下来,尝试在循环函数中使用并行函数似乎很奇怪。在外循环中进行并行化更为逻辑。嵌套并行计算中涉及的通信导致计算时间的急剧增加。你没有获得任何东西,因为你的sim
功能非常快。实际上,保持内部循环序列化更有意义,因为在这种情况下,一个内核上的计算时间会比通信中的开销大。
使用snowfall-package并使用apply for循环而不是for循环的插图。这也很天真,因为矢量化有很多可以获胜(见下文)。
library(snowfall)
sfInit(parallel=T,cpus=2)
#same avec, bvec, sim
system.time({
out <- sapply(avec,function(i) {
sapply(bvec,function(j){
sim(i,j)
})
})
})[3]
elapsed
0.33
sfExport("avec","bvec","sim")
system.time({
out <- sfSapply(avec,function(i) { # this one is parallel
sapply(bvec,function(j){ # this one is not, no sense in doing so
sim(i,j)
})
})
})[3]
elapsed
0.17
两个矩阵是相同的,除了由于结构的维度名称:
> all.equal(out1,out2)
[1] "Attributes: < Length mismatch: comparison on first 1 components >"
正确的R方式是:
system.time(
out3 <- outer(avec*10,bvec,"+")
)[3]
elapsed
0.01
明显更快,并创建一个相同的(虽然转置)矩阵:
> all.equal(out1,t(out3))
[1] TRUE
(作为参考,你的双重for循环在我的系统上运行0.73经过时间......)
答案 1 :(得分:0)
Joris Meys给了我一个很好的答案,here也适用于那种情况。对不起,“双帖”