【问题标题】:Memory Usage in Foreach FunctionForeach 函数中的内存使用情况
【发布时间】:2009-12-29 14:37:44
【问题描述】:

我想知道是否有任何方法可以让 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 做的持续数据移动。

【问题讨论】:

  • 我还想到因为doMC使用forkresults实际上不会在主进程中设置。您只能通过combine 函数组合结果。

标签: r foreach parallel-processing


【解决方案1】:

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

> 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 分钟后杀死它。

【讨论】:

    【解决方案2】:

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

    myfun<-function(arr){abind(arr,along=.5)}
    
    foreach(1:n.sims,.combine=myfun) .... 
    

    【讨论】:

      【解决方案3】:

      也许我在这里遗漏了一些东西。无论是在for-loop 还是通过foreach 调用,单个函数(i,j,data) 调用的成本应该是不变的。你能不能在串行模式下尝试foreach,然后试试multicore(除非你在Windows上)然后从那里开始?

      【讨论】:

      • 我想我对 doMC 结构的两个方面感到困惑。设置工作人员的固定成本是多少,移动数据的成本是多少。在我的例子中,运行函数(i,j,data)的单次迭代大约需要 200 秒,但在多核中同时运行两个需要大约 12 分钟。
      猜你喜欢
      • 1970-01-01
      • 2019-01-02
      • 1970-01-01
      • 2021-10-21
      • 2021-09-25
      • 1970-01-01
      • 1970-01-01
      • 2020-12-19
      • 1970-01-01
      相关资源
      最近更新 更多