`mclapply` 和 `foreach()` 循环工作过程的区别

ann*_*ann 5 parallel-processing r parallel.foreach mclapply doparallel

这是出于好奇而提出的一般性问题。我正在使用该doParallel包进行并行计算。我使用这些包来进行模拟。

我观察到,当我使用foreach循环进行模拟时,Rstudio 中的当前使用内存急剧上升 (4+GiB),并且 Rstudio 有时崩溃。

现在我再次parallel::mclapply进行了相同的模拟,但令人惊讶的是没有问题,并且当前使用内存没有增加太多(10+MiB)。

我不明白代码内部发生了什么。我期待对上述过程的详细解释。

sessionInfo()因为我的 R 是

R version 4.2.1 (2022-06-23) -- "Funny-Looking Kid"
Copyright (C) 2022 The R Foundation for Statistical Computing
Platform: aarch64-apple-darwin20 (64-bit)
Run Code Online (Sandbox Code Playgroud)

操作系统是MacOS。

doParallel软件包版本 1.0.17。

RStudio 版本 2023.03.01。

例子:

假设我们正在尝试计算 Erdos-Renyi 图的边数。我试图每次模拟图形并存储每次模拟的边计数值。

代码如下

#ER random graph generator
src1 <- {"#include <Rcpp.h>
using namespace Rcpp;
// [[Rcpp::export]]
NumericMatrix ER_AdjMatGEN_cpp(int N, double p){
  NumericMatrix temp(N,N);
  for(int i=0; i< N; i++){
    for(int j=0; j < i; j++){
        temp(i,j) = R::rbinom(1,p);
        temp(j,i) = temp(i,j);
    }
  }
  return temp;
}"}
Run Code Online (Sandbox Code Playgroud)
Niter <- 10000
#________________
edgeCnt_result1 <- foreach(icount(Niter),
                           v = iter(function() ER_AdjMatGEN_cpp(10000, 0.3)),
                           .combine = "rbind") %dopar% {
                             sum(v)
                           }
#___________
edgeCnt_result1 <- do.call(rbind, mclapply(1:Niter, function(i) {v = ER_AdjMatGEN_cpp(N = 10000, 0.3) 
return(sum(v))} , mc.cores = 7))
Run Code Online (Sandbox Code Playgroud)

当我尝试运行第一次迭代时,Rstudio 崩溃,但当我运行第二次迭代时,它运行正常。

Geo*_*hov 2

您的mclapply()代码首先生成完整的Niter长列表,然后将do.call()其全部绑定在一起。结果向量只有一种分配。

foreach()另一方面,.combine当列表元素变得可用时,用于重新绑定列表元素,随着结果向量的增长迭代地重新分配它。

相反,请使用的.multicombine.maxcombine参数foreach()。要模仿do.call(),请将第一个TRUE和第二个设置为Niter

有关更详细的说明,请参阅https://rpubs.com/jimhester/rbind 。