内部循环与外部函数

时间:2018-12-30 00:42:08

标签: r microbenchmark

在对各种解决方案进行基准测试时,来自this SO post

进行了讨论。考虑以下代码

# global environment is empty - new session just started
# set up
set.seed(20181231)
n <- sample(10^3:10^4,10^3)
for_loop <- function(n) {
  out <- integer(length(n))
  for(k in 1:length(out)) {
    if((k %% 2) == 0){
      out[k] <- 0L
      next
    }
    out[k] <- 1L
    next
  }
  out
}
# benchmarking
res <- microbenchmark::microbenchmark(
  for_loop = {
    out <- integer(length(n))
    for(k in 1:length(out)) {
      if((k %% 2) == 0){
        out[k] <- 0L
        next
      }
      out[k] <- 1L
      next
    }
    out
  },
  for_loop(n),
  times = 10^4
)

以下是完全相同的循环的基准测试结果,一个循环包装在一个函数中,另一个循环包装在

# Unit: microseconds
#        expr      min       lq      mean   median       uq      max neval cld
#    for_loop 3216.773 3615.360 4120.3772 3759.771 4261.377 34388.95 10000   b
# for_loop(n)  162.280  180.149  225.8061  190.724  211.875 26991.58 10000  a 
ggplot2::autoplot(res)

benchmarking2

可以看出,效率存在巨大差异。造成这种情况的根本原因是什么?

要清楚,问题不在于上述代码解决的任务(可以更优雅地完成),而不仅仅是常规循环和包装在函数内部的循环之间的效率差异。

1 个答案:

答案 0 :(得分:6)

解释是函数是“及时”编译的,而解释代码不是。有关说明,请参见?compiler::enableJIT

如果要演示差异,请运行

compiler::enableJIT(0)

任何代码之前(创建for_loop函数的包括)。这将禁用该会话其余部分的JIT编译。然后,这两组代码的时序将更加相似。

您必须在创建for_loop函数之前执行此操作,因为一旦JIT编译器对其进行编译,无论是否启用JIT,它都将保持编译状态。