2015-07-10 31 views
0

我正在使用for循环计算置换测试统计信息。我希望使用并行处理来加速这一点(特别是foreach包中的foreach)。 https://beckmw.wordpress.com/2014/01/21/a-brief-foray-into-parallel-processing-with-r/在R中并行处理的foreach(foreach包)

我的原代码:

library(foreach) 
library(doParallel) 
set.seed(10) 
x = rnorm(1000) 
y = rnorm(1000) 
n = length(x) 
nexp = 10000 
perm.stat1 = numeric(n) 
ptm = proc.time() 
for (i in 1:nexp){ 
    y = sample(y) 
    perm.stat1[i] = cor(x,y,method = "pearson") 
    } 
proc.time()-ptm 
# 1.321 seconds 

然而,当我用foreach循环,我得到的结果要慢得多:

cl<-makeCluster(8) 
registerDoParallel(cl) 
perm.stat2 = numeric(n) 
ptm = proc.time() 
perm.stat2 = foreach(icount(nexp), .combine=c) %dopar% { 
    y = sample(y) 
    cor(x,y,method = "pearson") 
} 
proc.time()-ptm 
stopCluster(cl) 
#3.884 seconds 

这是为什么我从下面的说明发生了什么?我做错了什么? 谢谢

回答

0

foreach循环中有更多的计算开销。这将返回一个列表,其中包含循环体的每次执行,然后通过参数.combine=c将其组合到一个向量中。 for循环不返回任何内容,而是将值赋给perm.stat1作为副作用,所以不需要任何额外开销。

看看Why is foreach() %do% sometimes slower than for?更深入的解释为什么foreach在许多情况下比for慢。其中foreach进入它自己的是当循环内部的操作是计算密集型的,使得通过比较返回列表中的每个值无关紧要的时间罚分。例如,上面的Wordpress文章中使用的rnormsummary的组合。

1

你越来越糟糕的表现,因为你分手了一个小问题变成万任务,每个大约需要毫秒执行的第八。当循环的主体需要很长一段时间(我曾说过至少10秒,但我现在已经把它丢到现在至少一秒)时,简单地将for循环变成foreach循环是可以的,但是,当任务很小时,简单的策略不起作用(在这种情况下,非常小,很小)。当任务很小时,您大部分时间都会花费时间发送任务并接收工作人员的结果。换句话说,通信开销大于计算时间。坦率地说,我很惊讶你没有得到太多糟糕的表现。

对我来说,它并没有真正似乎值得并行化需要不到两秒钟来执行的问题,但实际上你可以通过分块得到加快使用foreach。也就是说,你把问题分成更小的块,通常给每个工人一块。这里有一个例子:

nw <- getDoParWorkers() 
perm.stat1 <- 
    foreach(xnexp=idiv(nexp, chunks=nw), .combine=c) %dopar% { 
    p = numeric(xnexp) 
    for (i in 1:xnexp) { 
     y = sample(y) 
     p[i] = cor(x,y,method="pearson") 
    } 
    p 
    } 

正如你所看到的,foreach循环分裂问题成块,并且循环体包含原始顺序代码的修改版本,现在在整个的一小部分工作问题。

在我的四核心Mac笔记本电脑上,它执行时间为0.447秒,而顺序版本为1.245秒。这看起来像是一个非常可敬的速度。