Foreach函数中的内存使用

时间:2009-12-29 14:37:44

标签: r foreach parallel-processing

我想知道是否有办法让R中的foreach包使用预先分配的结构来放置结果。基本上它涉及很多大型数据集上的小型linalg操作。

我的非foreach原始代码类似于

results <- rep(NA,m*l*[big.number])
dim(results) <- c(m,l,[big.number])
for (i in 1:m){
    for (j in 1:l){
        results[i,j,] <- function(j,i,data)
    }
}

我想使用foreach和doMC来并行化这个,但测试运行真的非常慢,我认为这是rbind和c所做的持续数据移动。

3 个答案:

答案 0 :(得分:2)

这不是答案,但我想我会发布一些测试结果,希望其他人知道发生了什么:

> data <- matrix(rnorm(1000 * 10000), nrow=10000)
> system.time(foreach(j=1:1000, .combine = function(...) NULL, .multicombine=TRUE) %do% { sum(data[,j]) })
utilisateur     système      écoulé 
      0.643       0.031       0.674 
> system.time(foreach(j=1:1000, .combine = function(...) NULL, .multicombine=TRUE) %dopar% { sum(data[,j]) })
utilisateur     système      écoulé 
      0.613       0.215       0.653 
> system.time(foreach(j=1:1000) %dopar% { sum(data[,j]) })
utilisateur     système      écoulé 
      0.537       0.122       0.745 
> system.time(foreach(j=1:1000) %do% { sum(data[,j]) })
utilisateur     système      écoulé 
      0.650       0.028       0.681 
> system.time (for (j in 1:1000) { sum(data[,j]) })
utilisateur     système      écoulé 
      0.153       0.069       0.222 

简而言之,使用内置for仍然比串行foreach更快。你并没有真正使用dopar赢得胜利,似乎并不是把所有东西放在一起就是一直在进行的(可能仍然需要将数据传回主人需要很长时间)。你也可以说,通过计算这么简单,开销自然会占主导地位。所以让我们做一些更复杂的事情:

> data <- matrix(rnorm(3000 * 10000), nrow=10000)
> system.time (for(j in 1:6000) { sum(lgamma(exp(data[,(j - 1) %% 3000 + 1]))) })
utilisateur     système      écoulé 
     11.215       1.272      12.490 
> system.time (foreach(j=1:6000, .combine=c) %do% { sum(lgamma(exp(data[,(j - 1) %% 3000 + 1]))) })
utilisateur     système      écoulé 
     14.304       0.468      15.788
> system.time (foreach(j=1:6000, .combine=c) %dopar% { sum(lgamma(exp(data[,(j - 1) %% 3000 + 1]))) })
utilisateur     système      écoulé 
     14.377      11.839      10.358 

现在dopar开始胜出,但这三者仍然具有可比性,内置for并不是那么糟糕,即使有了额外的工作。但是沟通开销呢?我们只返回转换后的数据(每次迭代10,000个数字),而不是取总和。

> system.time (for(j in 1:6000) { lgamma(exp(data[,(j - 1) %% 3000 + 1])) })
utilisateur     système      écoulé 
     11.092       1.189      12.302     
> system.time (foreach(j=1:6000, .combine=function (...) NULL, .multicombine=TRUE) %do% { lgamma(exp(data[,(j - 1) %% 3000 + 1])) })
utilisateur     système      écoulé 
     14.902       1.867      22.901 
> system.time (foreach(j=1:6000, .combine=function (...) NULL, .multicombine=TRUE) %dopar% { lgamma(exp(data[,(j - 1) %% 3000 + 1])) })

^C

Timing stopped at: 2.155 0.706 241.948 
> 

在这里,for循环不需要为保持结果而烦恼,需要与之前一样长。这次%do%版本耗费了很长时间。 %dopar%可能通过共享内存传输结果?我决定在大约4分钟后杀死它。

答案 1 :(得分:0)

也许我在这里遗漏了一些东西。单个函数(i,j,data)调用的成本应该是在for - 循环中调用还是通过foreach调用的。您是否可以在串行模式下尝试foreach,然后尝试multicore(除非您在Windows上)并从那里开始?

答案 2 :(得分:0)

我很幸运abind()(来自图书馆(abind))。例如,假设我有一个返回矩阵的模拟函数,我想要一个大数组,我可以使用abind(,沿= .5)来获取要绑定到数组中的矩阵列表,并添加一个新的维度。所以你可能喜欢这样的东西:

myfun<-function(arr){abind(arr,along=.5)}

foreach(1:n.sims,.combine=myfun) ....