Rcpp 函数比 Rf_eval 慢 [英] Rcpp Function slower than Rf_eval

查看:32
本文介绍了Rcpp 函数比 Rf_eval 慢的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我一直在开发一个包,该包使用 Rcpp 将任意 R 代码应用于一组大型医学成像文件.我注意到我的 Rcpp 实现比原始的纯 C 版本慢得多.我追踪了通过 Function 调用函数与原始 Rf_eval 的区别.我的问题是为什么会出现接近 4 倍的性能下降,有没有办法加快函数调用的速度,使其在性能上更接近 Rf_eval?

I have been working on a package that uses Rcpp to apply arbitrary R code over a group of large medical imaging files. I noticed that my Rcpp implementation is considerably slower than the original pure C version. I traced the difference to calling a function via Function, vs the original Rf_eval. My question is why is there a close to 4x performance degradation, and is there a way to speed up the function call to be closer in performance to Rf_eval?

示例:

library(Rcpp)                                                                                                                                                          
library(inline)                                                                                                                                                        
library(microbenchmark)                                                                                                                                                

cpp_fun1 <-                                                                                                                                                            
  '                                                                                                                                                                    
Rcpp::List lots_of_calls(Function fun, NumericVector vec){                                                                                                             
  Rcpp::List output(1000);                                                                                                                                             
  for(int i = 0; i < 1000; ++i){                                                                                                                                       
    output[i] = fun(NumericVector(vec));                                                                                                                               
  }                                                                                                                                                                    
  return output;                                                                                                                                                       
}                                                                                                                                                                      
'                                                                                                                                                                      

cpp_fun2 <-                                                                                                                                                            
  '                                                                                                                                                                    
Rcpp::List lots_of_calls2(SEXP fun, SEXP env){                                                                                                                         
  Rcpp::List output(1000);                                                                                                                                             
  for(int i = 0; i < 1000; ++i){                                                                                                                                       
    output[i] = Rf_eval(fun, env);                                                                                                                                     
  }                                                                                                                                                                    
  return output;                                                                                                                                                       
}                                                                                                                                                                      
'                                                                                                                                                                      

lots_of_calls <- cppFunction(cpp_fun1)                                                                                                                                 
lots_of_calls2 <- cppFunction(cpp_fun2)                                                                                                                                

microbenchmark(lots_of_calls(mean, 1:1000),                                                                                                                            
               lots_of_calls2(quote(mean(1:1000)), .GlobalEnv))

结果

Unit: milliseconds
                                            expr      min       lq     mean   median       uq      max neval
                     lots_of_calls(mean, 1:1000) 38.23032 38.80177 40.84901 39.29197 41.62786 54.07380   100
 lots_of_calls2(quote(mean(1:1000)), .GlobalEnv) 10.53133 10.71938 11.08735 10.83436 11.03759 18.08466   100

推荐答案

Rcpp 很棒,因为它让程序员干净看起来很荒谬.清洁度会以模板化响应和一组会降低执行时间的假设的形式产生成本.但是,通用代码设置与特定代码设置就是这种情况.

Rcpp is great because it makes things look absurdly clean to the programmer. The cleanliness has a cost in the form of templated responses and a set of assumptions that weigh down the execution time. But, such is the case with a generalized vs. specific code setup.

Rcpp::Function.对 Rf_reval 的修改版本的初始构造和外部调用需要一个特殊的 Rcpp 特定的 eval 函数,在 Rcpp_eval.h.反过来,当通过 Shield 与之关联.等等……

Take for instance the call route for an Rcpp::Function. The initial construction and then outside call to a modified version of Rf_reval requires a special Rcpp specific eval function given in Rcpp_eval.h. In turn, this function is wrapped in protections to protect against a function error when calling into R via a Shield associated with it. And so on...

相比之下,Rf_eval 两者都没有.如果它失败了,您将在没有桨的情况下爬上小溪.(当然,除非您实施通过 R_tryEval 捕获错误.)

In comparison, Rf_eval has neither. If it fails, you will be up the creek without a paddle. (Unless, of course, you implement error catching via R_tryEval for it.)

话虽如此,加速计算的最好方法是简单地用 C++ 编写计算所需的一切.

With this being said, the best way to speed up the calculation is to simply write everything necessary for the computation in C++.

这篇关于Rcpp 函数比 Rf_eval 慢的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆