本机 R 函数的速度与 C++ 等效函数的速度
Speed of native R function vs C++ equivalent
当我将 R 中的原生 Gamma 函数 gamma
的速度与 C++ 等效函数 std::tgamma
的速度进行比较时,我发现后者大约慢 10-15 倍。为什么?我预计会有一些差异,但这很大,不是吗?
我的实现:
library("Rcpp")
library("microbenchmark")
cppFunction("
double gammacpp(double x) {
return(std::tgamma(x));
}
")
x = max(0, rnorm(1, 50, 25))
microbenchmark(gamma(x), gammacpp(x))
我机器上的结果:
Unit: nanoseconds
expr min lq mean median uq max neval cld
gamma(x) 100 101 124.91 101 102 1001 100 a
gammacpp(x) 1000 1101 1302.98 1200 1300 9401 100 b
查看gamma()
的代码(例如输入gamma<Return>
):它只是调用了一个原语。
您的 Rcpp
功能设置得 方便 。只需要 two-liner。但它有一些 一些 开销是保存 random-number 生成器的状态,设置 try
/catch
块用于异常处理等等。我们已经记录了如何跳过这些步骤中的 一些 ,但在许多情况下是 ill-advised.
简而言之,我认为您的比较选择不当:您进行基准测试的功能发生的事情太少了。还要注意单位:纳秒。你这里有很多测量错误。
但鼓舞士气的是,使用 'naive'(方便的)C++ 函数作为您编写的 one-liner,您将不会打败一些优化和调整 已经从 R 内部编译 代码。这实际上是一件好事,因为如果你这样做,你现在必须重写大块的 R。
编辑: 对于 kicks,这是第三个变体 'in the middle',我们使用 Rcpp
来调用 R 的相同 C API .
代码
#include <Rcpp.h>
// [[Rcpp::export]]
double gammaStd(double x) { return (std::tgamma(x)); }
// [[Rcpp::export]]
Rcpp::NumericVector gamma_R(Rcpp::NumericVector x) { return (Rcpp::gamma(x)); }
/*** R
set.seed(123)
x <- max(0, rnorm(1, 50, 25))
res <- microbenchmark::microbenchmark(R = gamma(x), Cpp = gammaStd(x), Sugar = gamma_R(x) )
res
*/
输出
> Rcpp::sourceCpp("~/git/Whosebug/72383007/answer.cpp")
> set.seed(123)
> x <- max(0, rnorm(1, 50, 25))
> res <- microbenchmark::microbenchmark(R = gamma(x), Cpp = gammaStd(x), Sugar = gamma_R(x) )
>
res
Unit: nanoseconds
expr min lq mean median uq max neval cld
R 102 112.0 136.95 124 134.5 1068 100 a
Cpp 1111 1155.5 11930.02 1186 1260.0 1054813 100 a
Sugar 1142 1201.0 6355.92 1246 1301.5 506628 100 a
>
当我将 R 中的原生 Gamma 函数 gamma
的速度与 C++ 等效函数 std::tgamma
的速度进行比较时,我发现后者大约慢 10-15 倍。为什么?我预计会有一些差异,但这很大,不是吗?
我的实现:
library("Rcpp")
library("microbenchmark")
cppFunction("
double gammacpp(double x) {
return(std::tgamma(x));
}
")
x = max(0, rnorm(1, 50, 25))
microbenchmark(gamma(x), gammacpp(x))
我机器上的结果:
Unit: nanoseconds
expr min lq mean median uq max neval cld
gamma(x) 100 101 124.91 101 102 1001 100 a
gammacpp(x) 1000 1101 1302.98 1200 1300 9401 100 b
查看gamma()
的代码(例如输入gamma<Return>
):它只是调用了一个原语。
您的 Rcpp
功能设置得 方便 。只需要 two-liner。但它有一些 一些 开销是保存 random-number 生成器的状态,设置 try
/catch
块用于异常处理等等。我们已经记录了如何跳过这些步骤中的 一些 ,但在许多情况下是 ill-advised.
简而言之,我认为您的比较选择不当:您进行基准测试的功能发生的事情太少了。还要注意单位:纳秒。你这里有很多测量错误。
但鼓舞士气的是,使用 'naive'(方便的)C++ 函数作为您编写的 one-liner,您将不会打败一些优化和调整 已经从 R 内部编译 代码。这实际上是一件好事,因为如果你这样做,你现在必须重写大块的 R。
编辑: 对于 kicks,这是第三个变体 'in the middle',我们使用 Rcpp
来调用 R 的相同 C API .
代码
#include <Rcpp.h>
// [[Rcpp::export]]
double gammaStd(double x) { return (std::tgamma(x)); }
// [[Rcpp::export]]
Rcpp::NumericVector gamma_R(Rcpp::NumericVector x) { return (Rcpp::gamma(x)); }
/*** R
set.seed(123)
x <- max(0, rnorm(1, 50, 25))
res <- microbenchmark::microbenchmark(R = gamma(x), Cpp = gammaStd(x), Sugar = gamma_R(x) )
res
*/
输出
> Rcpp::sourceCpp("~/git/Whosebug/72383007/answer.cpp")
> set.seed(123)
> x <- max(0, rnorm(1, 50, 25))
> res <- microbenchmark::microbenchmark(R = gamma(x), Cpp = gammaStd(x), Sugar = gamma_R(x) )
>
res
Unit: nanoseconds
expr min lq mean median uq max neval cld
R 102 112.0 136.95 124 134.5 1068 100 a
Cpp 1111 1155.5 11930.02 1186 1260.0 1054813 100 a
Sugar 1142 1201.0 6355.92 1246 1301.5 506628 100 a
>