【问题标题】:Is it more efficient to declare helper functions outside the main function?在主函数之外声明辅助函数是否更有效?
【发布时间】:2021-05-26 01:41:48
【问题描述】:

当我一步步调试这种功能时:

foo <- function(x) {
  helper <- function(x) x^2
  2 * helper(x)
}

我看到每次都会评估辅助函数定义。在调试模式下是否相同?在时间执行方面是不是很糟糕?

【问题讨论】:

  • 是的。不,不是。与调用函数相比,定义函数更便宜。我建议您做一些基准测试来确认这一点。
  • @Roland 比调用它便宜,当然,但成本仍然不小:R 将评估函数定义每次调用外部函数。

标签: r performance functional-programming


【解决方案1】:

你可以自己试试。我没有看到太大的不同。当我尝试时,内部或外部在不同的运行中更快。

library(microbenchmark)

foo1 <- function(x) {
  helper <- function(x) x^2
  2 * helper(x)
}

helper <- function(x) x^2
foo2 <- function(x) {
  2 * helper(x)
}

microbenchmark(
  inside = foo1(1:1000),
  outside = foo2(1:1000),
  times = 1000
)

【讨论】:

  • 看看关闭 JIT 编译器是否会改变基准测试会很有趣。
  • @Roland 是否在 REPL JIT 中获取或输入函数?我以为只有包加载会导致 JITtin 默认情况下。
  • 如果helper 的定义不重要,看看会发生什么会很有趣。
  • @KonradRudolph 我不是这方面的专家。我知道 JIT 编译器改进了循环调用的代码。该代码不必来自包。 (这就是为什么,因为现在有几个 R 版本,在循环中增长一个对象并不总是低效的。)
  • @Roland 在循环中增长对象效率低下,因为在每次迭代时都会复制增加的内存,除非在增加的块中保留内存。这不是 JIT 可以解决的问题,而是通过在接收数据结构中逐步保留内存来解决的。
【解决方案2】:

根据@John Coleman 的评论,我已经尝试过了:

library(microbenchmark)

foo1 <- function(x) {
  helper <- function(x) {
    nested_helper <- function(y) {
      depper_helper <- function(z) {
        z + z
      }
      3 * depper_helper(y)
    }
    nested_helper(x) ^ 2
  }
  2 * helper(x)
}


nested_helper <- function(y) {
  3 * depper_helper(y)
}
depper_helper <- function(z) {
  z + z
}
helper <- function(x) {
  nested_helper(x) ^ 2
}
foo2 <- function(x) {
  2 * helper(x)
}

microbenchmark(
  inside = foo1(1:1000),
  outside = foo2(1:1000),
  times = 1000000
)

我运行了两次,得到了相同的结果:

Unit: microseconds
    expr min  lq     mean median  uq     max neval
  inside 5.0 5.4 8.822796    5.8 8.5 50905.9 1e+06
 outside 4.9 5.2 8.559778    5.6 8.3 47797.3 1e+06

内部定义似乎有点慢,但不是很明显。 JIT 编译器必须进行某种优化。我想确认一下。

【讨论】:

  • compiler::enableJIT(0) 关闭编译器。默认为compiler::enableJIT(3)。然而,函数定义仍然不是我们认为不平凡的。我相信 John 的意思是 helper 有几百行代码。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2016-05-29
  • 2020-10-22
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多