性能.Primitive和.Internal

时间:2015-05-12 14:45:26

标签: r

我通过从流程中删除一步来进行一些优化......

> library(microbenchmark)
> microbenchmark(paste0("this","and","that"))
Unit: microseconds
                          expr   min    lq    mean median    uq    max neval
 paste0("this", "and", "that") 2.026 2.027 3.50933  2.431 2.837 34.038   100

> microbenchmark(.Internal(paste0(list("this","and","that"),NULL)))
Unit: microseconds
                                                 expr   min    lq    mean median    uq    max neval
 .Internal(paste0(list("this", "and", "that"), NULL)) 1.216 1.621 2.77596  2.026 2.027 43.764   100

到目前为止一直很好......

然后我注意到list被定义为

function (...)  .Primitive("list")

我试图进一步简化"

> microbenchmark(.Internal(paste0(.Primitive("list")("this","and","that"),NULL)))
Unit: microseconds
                                                               expr   min    lq    mean median    uq    max neval
 .Internal(paste0(.Primitive("list")("this", "and", "that"), NULL)) 3.241 3.242 4.66433  3.647 3.648 80.638   100

时间增加了!

我的猜测是处理字符串"list"是问题的根源,并且在实际调用函数list

中处理它的方式不同

但是如何?

免责声明:我知道这会伤害可读性,而不是帮助提高性能。这仅适用于一些非常简单的功能,这些功能不会改变,并且经常使用,即使按此成本也需要轻微的性能问题。

编辑以回应Josh O&Brien的评论:

我不确定这说明他的想法,但是

library(compiler)
ff <- compile(function(...){.Internal(paste0(.Primitive("list")("this","and","that"),NULL))})
ff2 <- compile(function(...){.Internal(paste0(list("this","and","that"),NULL))})
microbenchmark(eval(ff),eval(ff2),times=10000)
> microbenchmark(eval(ff2),eval(ff),times=10000)
Unit: microseconds
      expr   min    lq     mean median    uq     max neval
 eval(ff2) 1.621 2.026 2.356761  2.026 2.431 144.257 10000
  eval(ff) 1.621 2.026 2.455913  2.026 2.431  89.148 10000

并查看从microbenchmark生成的图表(只需用plot()包裹它来自己查看)运行了很多次,看起来那些具有统计上相同的性能,尽管&#34; max&# 34;看起来像ff2的值有一个更糟糕的最坏情况。不知道该怎么做,但也许这会对某人有所帮助。所有这些基本上都说他们编译成相同的代码。这是否意味着他的评论是答案?

2 个答案:

答案 0 :(得分:11)

// You can use $this->encrypter afterwards $this->load->library('encrypt', NULL, 'encrypter'); 较慢的原因似乎是因为Josh O'Brien猜测的结果。直接调用.Internal(paste0(.Primitive("list")("this","and","that"),NULL))会产生一些额外的开销。

您可以通过一个简单的例子看到效果:

.Primitive("list")

也就是说,您无法从R提示中提高require(compiler) pl <- cmpfun({.Primitive("list")}) microbenchmark(list(), .Primitive("list")(), pl()) # Unit: nanoseconds # expr min lq median uq max neval # list() 63 98.0 112.0 140.5 529 100 # .Primitive("list")() 4243 4391.5 4486.5 4606.0 16077 100 # pl() 79 135.5 148.0 175.5 39108 100 .Primitive的速度。它们都是C代码的入口点。

并且没有理由尝试用.Internal替换.Primitive的来电。这是递归的,因为.Internal 本身就是一个原语。

.Internal

如果您尝试直接调用> .Internal function (call) .Primitive(".Internal") “并且如果您编译”直接“调用时类似的”加速“,那么您会得到同样的缓慢。

.Internal

答案 1 :(得分:0)

R解释器对常见函数进行了硬编码优化,这比字节编译更深入:

> list2 <- list
> list3 <- cmpfun(list2)
> microbenchmark(
+   list(1,2),
+   list2(1,2),
+   list3(1,2)
+ )
Unit: nanoseconds
        expr min    lq    mean median    uq   max neval
  list(1, 2) 576 620.5  654.53  640.0 675.5   941   100
 list2(1, 2) 619 702.0 1123.43  728.0 761.0 39045   100
 list3(1, 2) 617 683.0  735.83  715.5 759.0  1964   100

这是SEXP的样子。请注意&#34; list&#34;

上的元数据
> .Internal(inspect(quote(list(1,2))))
@23b0ed0 06 LANGSXP g0c0 [NAM(2)] 
  @1ed8f48 01 SYMSXP g1c0 [MARK,LCK,gp=0x4000] "list" (has value)
  @2c7adf8 14 REALSXP g0c1 [] (len=1, tl=0) 1
  @2c7adc8 14 REALSXP g0c1 [] (len=1, tl=0) 2

list2缺少一些元数据:

> list2 <- list
> .Internal(inspect(quote(list2(1,2))))
@23b1578 06 LANGSXP g0c0 [NAM(2)] 
  @23b0a70 01 SYMSXP g0c0 [] "list2"
  @2c7ad08 14 REALSXP g0c1 [] (len=1, tl=0) 1
  @2c7acd8 14 REALSXP g0c1 [] (len=1, tl=0) 2

.Primitive("list")是一个更复杂的表达方式:

> .Internal(inspect(quote(.Primitive("list")(1,2))))
@297e748 06 LANGSXP g0c0 [NAM(2)] 
  @297d9a0 06 LANGSXP g0c0 [] 
    @1ec4530 01 SYMSXP g1c0 [MARK,LCK,gp=0x4000] ".Primitive" (has value)
    @2c7a888 16 STRSXP g0c1 [] (len=1, tl=0)
      @1ed5588 09 CHARSXP g1c1 [MARK,gp=0x61] [ASCII] [cached] "list"
  @2c7a858 14 REALSXP g0c1 [] (len=1, tl=0) 1
  @2c7a828 14 REALSXP g0c1 [] (len=1, tl=0) 2