【问题标题】:How to use the doSMP and the foreach packages correctly?如何正确使用 doSMP 和 foreach 包?
【发布时间】:2011-03-16 12:42:38
【问题描述】:

我正在尝试使用为 foreach 包提供并行后端的 doSMP package

你能指出我做错了什么吗?确实,以这种方式使用 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 迁移过来的。

【问题讨论】:

标签: r multicore


【解决方案1】:

我个人不喜欢 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 时间...)

【讨论】:

  • 感谢您的回答。我还需要研究降雪包。但是,我会对您的回答发表评论。我不认为使用 foreach 会自动并行化该过程。为此,我认为必须将 foreach 与 %dopar% 结合使用。再次感谢您
  • @Marco:确实。但是您并行化内部循环,而不是外部循环。我编辑了我的答案。
  • 好的,现在我很清楚了!我可以理解为什么计算时间会增加。再次感谢您!
【解决方案2】:

Joris Meys 给了我一个很好的答案 here 在这种情况下也成立。对不起“双重发布”

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2019-03-21
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2020-02-18
    • 1970-01-01
    • 2014-11-15
    相关资源
    最近更新 更多