首页 > 解决方案 > 没有内联/创建本地包的 Rcpp 并行化

问题描述

我正在创建一个包,希望最终能放到 CRAN 上。C++我已经在的帮助下编写了大部分包,Rcpp现在希望启用此C++代码的并行化。我正在使用该软件包,但是,如果这会更好foreach,我愿意切换到其他库或其他库。snow

我首先尝试并行化一个简单的函数:

#include <RcppArmadillo.h>
// [[Rcpp::depends(RcppArmadillo)]]
using namespace Rcpp;


// [[Rcpp::export]]
arma::vec rNorm_c(int length) {
  return arma::vec(length, arma::fill::randn);
}


/*** R

n_workers <- parallel::detectCores(logical = F)
cl <- parallel::makeCluster(n_workers)
doParallel::registerDoParallel(cl)

n <- 10
library(foreach)

foreach(j = rep(n, n), 
        .noexport = c("rNorm_c"), 
        packages = "Rcpp") %dopar% {rNorm_c(j)}
*/

我添加了.noexport因为没有,我得到了错误Error in { : task 1 failed - "NULL value passed as symbol address"。这使我看到了这篇建议这样做的 SO 帖子。

但是,我现在收到错误Error in { : task 1 failed - "could not find function "rNorm_c""消息,大概是因为我没有按照最佳答案说明在每个节点上分别加载函数。我不确定如何做到这一点。

这个 SO 帖子演示了如何通过编写C++内联代码来做到这一点,但是,由于C++我的包的代码是多个函数,这可能不是最好的解决方案。这篇 SO 帖子建议为工作人员创建一个本地包以加载和调用,但是,由于我希望在 CRAN 包中提供此代码,除非我想要,否则似乎无法使用本地包尝试发布两个 CRAN 包。

任何有关如何处理此问题的建议或对 Rcpp 代码并行化资源的参考将不胜感激。

编辑:

我使用上述函数创建了一个名为rnormParallelization. 在这个包中,我还包含了几个 R 函数,其中一个利用包来并行化使用该函数snow的 for 循环:rNorm_c

rNorm_samples_for <- function(num_samples, length){
  sample_mat <- matrix(NA, length, num_samples)
  for (j in 1:num_samples){
    sample_mat[ , j] <- rNorm_c(length)
  }
  return(sample_mat)
}

rNorm_samples_snow1 <- function(num_samples, length){
  clus <- snow::makeCluster(3)
  snow::clusterExport(clus, "rNorm_c") 
  out <- snow::parSapply(clus, rep(length, num_samples), rNorm_c)
  snow::stopCluster(clus)
  return(out)
}

这两个功能都按预期工作:

> rNorm_samples_for(2, 3)
            [,1]       [,2]
[1,] -0.82040308 -0.3284849
[2,] -0.05169948  1.7402912
[3,]  0.32073516  0.5439799

> rNorm_samples_snow1(2, 3)
            [,1]       [,2]
[1,] -0.07483493  1.3028315
[2,]  1.28361663 -0.4360829
[3,]  1.09040771 -0.6469646

但是,并行版本的工作速度要慢得多:

> microbenchmark::microbenchmark(
+   rnormParallelization::rNorm_samples_for(1e3, 1e4),
+   rnormParallelization::rNorm_samples_snow1(1e3, 1e4)
+ )
Unit: milliseconds
                                                   expr       min        lq
   rnormParallelization::rNorm_samples_for(1000, 10000)  217.0871  249.3977
 rnormParallelization::rNorm_samples_snow1(1000, 10000) 1242.8315 1397.7643
      mean    median        uq       max neval
  320.5456  285.9787  325.3447  802.7488   100
 1527.0406 1482.5867 1563.0916 3411.5774   100

这是我的会话信息:

> sessionInfo()
R version 4.1.1 (2021-08-10)
Platform: x86_64-w64-mingw32/x64 (64-bit)
Running under: Windows 10 x64 (build 19043)

Matrix products: default

locale:
[1] LC_COLLATE=English_United States.1252 
[2] LC_CTYPE=English_United States.1252   
[3] LC_MONETARY=English_United States.1252
[4] LC_NUMERIC=C                          
[5] LC_TIME=English_United States.1252    

attached base packages:
[1] stats     graphics  grDevices utils     datasets  methods   base     

other attached packages:
[1] rnormParallelization_1.0

loaded via a namespace (and not attached):
[1] microbenchmark_1.4-7 compiler_4.1.1       snow_0.4-4          
[4] parallel_4.1.1       tools_4.1.1          Rcpp_1.0.7   

包含这两个脚本的 GitHub 存储库

标签: rrcppr-packageparallel-foreach

解决方案


推荐阅读