代码之家  ›  专栏  ›  技术社区  ›  niko

循环内部与外部函数

  •  2
  • niko  · 技术社区  · 6 年前

    由于 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 回复  |  直到 6 年前
        1
  •  6
  •   user2554330    6 年前

    解释是,函数是“及时”编译的,而解释代码则不是。见 ?compiler::enableJIT 以获取描述。

    如果您想演示差异,请运行

    compiler::enableJIT(0)
    

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

    在创建 福尔环 函数,因为一旦它被JIT编译器编译,不管是否启用了JIT,它都将保持编译状态。

    推荐文章