【发布时间】:2014-04-18 23:54:56
【问题描述】:
虽然 C++,特别是 Rcpp 包在加速我的代码方面对我有很大帮助,但我注意到我的 C++ 函数有一个列表或数据框输入参数(Rcpp::DataFrame 和 Rcpp:: 形式的参数) List) 与我的其他 C++ 函数相比非常慢。我写了一个示例代码,我想请教一些可以让我的代码更快的技巧:
首先,让我们在 R 中模拟一个 List,其中包含两个 List。将 myList 视为包含两个列表 - measure1 和 measure2 的列表。 measure1 和 measure2 本身就是列表,每个列表都包含对象的测量向量。这是R代码:
lappend <- function(lst, ...){
lst <- c(lst, list(...))
return(lst)
}
nSub <- 30
meas1 <- list()
meas2 <- list()
for (i in 1:nSub){
meas1 <- lappend(meas1, rnorm(10))
meas2 <- lappend(meas2, rnorm(10))
}
myList <- list(meas1 = meas1, meas2 = meas2)
现在,假设我想要一个 C++ 函数,为每个主题找到 measure1 的总和和 measure 2 的总和,然后根据这两个总和创建两个新的测量。最后,该函数应将这些新测量值作为列表返回。
// [[Rcpp::depends(RcppArmadillo)]]
#include <RcppArmadillo.h>
#include <Rcpp.h>
// [[Rcpp::export]]
Rcpp::List mySlowListFn(Rcpp::List myList, int nSub){
arma::vec myMult(nSub);
arma::vec myDiv(nSub);
for (int i = 0; i < nSub; i++){
arma::vec meas1_i = Rcpp::as<arma::vec>(Rcpp::as<Rcpp::List>(myList["meas1"])[i]);
arma::vec meas2_i = Rcpp::as<arma::vec>(Rcpp::as<Rcpp::List>(myList["meas2"])[i]);
myMult[i] = arma::sum(meas1_i)*arma::sum(meas2_i);
myDiv[i] = arma::sum(meas1_i)/arma::sum(meas2_i);
}
return Rcpp::List::create(Rcpp::Named("myMult") = myMult,
Rcpp::Named("myDiv") = myDiv);
}
我怎样才能使上面的功能更快?我特别在寻找将输入和输出列表保留在代码中的想法(因为在我自己的程序中处理列表是不可避免的),但有一些技巧可以减少一些开销时间。我想到的一件事是:
Rcpp::List mySlowListFn(const Rcpp::List& myList, int nSub)
非常感谢您的帮助。
【问题讨论】:
-
你的问题结束于一个开放的猜想,你可以(我敢补充说,应该)测试。
-
您可以尝试一些技巧,例如使用糖函数或使用不复制的犰狳向量的构造函数。我不确定为什么列表会很慢。
-
@DirkEddelbuettel,您好 Dirk,我实际测试了它,我没有发现使用指针或使用 myList 本身之间有任何区别,这非常令人惊讶!考虑另一个调用 mySlowListFn above() 的函数。如果我们用指向 myList 的指针参数定义 mySlowListFn,我应该如何在 callerFn 中调用这个函数?我可以直接使用 use myList 作为参数还是我应该把它的地址,因为它假设是一个指针?我试图理解为什么使用指针技巧并没有让我的代码更快,我不确定我是否正确使用了这个技巧。非常感谢您的帮助。
-
没有区别因为我们通过
SEXP类型与R接口已经是指针。添加const &只是C++ 级别的装饰。你射错了目标。 -
@Sameer,感谢 sameer 的评论。您特别指的是哪些糖功能?同样关于犰狳 vec 的想法,事实是我想在函数中保留列表,因为在我的原始代码中我必须使用 List 并且我想学习如何处理列表以制作我的原始函数兴趣更快。