【发布时间】:2019-08-28 13:25:53
【问题描述】:
我在 C++ 和 R 方面有一些经验,但我是 Rcpp 的新手。最近我在之前的一些项目中使用 Rcpp 取得了巨大的成功,因此决定将它应用到一个新项目中。我很惊讶我的 Rcpp 代码可能比相应的 R 函数慢得多。我试图简化我的 R 函数以找出原因,但找不到任何线索。非常欢迎您的帮助和 cmets!
比较 R 和 Rcpp 实现的主要 R 函数:
main <- function(){
n <- 50000
Delta <- exp(rnorm(n))
delta <- exp(matrix(rnorm(n * 5), nrow = n))
rx <- matrix(rnorm(n * 20), nrow = n)
print(microbenchmark(c1 <- test(Delta, delta, rx), times = 500))
print(microbenchmark(c2 <- rcpp_test(Delta, delta, rx), times = 500))
identical(c1, c2)
list(c1 = c1, c2 = c2)
}
R 实现:
test <- function(Delta, delta, rx){
const <- list()
for(i in 1:ncol(delta)){
const[[i]] <- rx * (Delta / (1 + delta[, i]))
}
const
}
Rcpp 实现:
#include <Rcpp.h>
using namespace Rcpp;
// [[Rcpp::export]]
List rcpp_test(NumericVector Delta,
NumericMatrix delta,
NumericMatrix rx) {
int n = Delta.length();
int m = rx.ncol();
List c;
NumericMatrix c1;
for(int i = 0; i < delta.ncol(); ++i){
c1 = NumericMatrix(n, m);
for(int k = 0; k < n; ++k){
double tmp = Delta[k] / (1 + delta(k, i));
for(int j = 0; j < c1.ncol(); ++j){
c1(k, j) = rx(k, j) * tmp;
}
}
c.push_back(c1);
}
return c;
}
我知道使用 Rcpp 并不能保证提高效率,但是鉴于我在这里展示的简单示例,我不明白为什么 Rcpp 代码运行如此缓慢。
Unit: milliseconds
expr min lq mean median uq max neval
c1 <- test(Delta, delta, rx) 13.16935 14.19951 44.08641 30.43126 73.78581 115.9645 500
Unit: milliseconds
expr min lq mean median uq max neval
c2 <- rcpp_test(Delta, delta, rx) 143.1917 158.7481 171.6116 163.413 173.7677 247.5495 500
理想情况下,rx 是我项目中的矩阵列表。 for 循环中的变量i 将用于选择一个元素进行计算。一开始我怀疑将List 传递给Rcpp 可能会有很高的开销,所以在这个例子中,我假设rx 是一个用于所有i 的固定矩阵。似乎这不是缓慢的原因。
【问题讨论】:
-
在 C++ 中,
push_back()在性能方面可能会花费很多,在需要快速执行速度的应用程序中应避免使用。最好事先分配所需的内存。 -
@RHertel 感谢您的评论。但在这个例子中,像 Ralf Stubner 所做的那样分配列表
c并没有多大帮助。请参考我对 Ralf Stubner 的回答。 -
请注意,我确实 not 将我的评论作为对您问题的回答,因为我确实 not 声明
push_back()的使用是代码速度低的主要原因。我说的是push_back()可以消耗相当多的性能,最好在开始时分配内存。此外,我认为指出在循环中动态增长对象是不好的编程风格是有用的。