这篇SO文章引发了一场关于对各种解决方案进行基准测试的讨论。
# 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)
由此可见,两者在效率上有很大的差距,究竟是甚么原因呢?
需要说明的是,问题不在于上面的代码所解决的任务(可以更优雅地完成),而仅仅在于常规循环和函数中 Package 的循环之间的效率差异。
1条答案
按热度按时间3wabscal1#
解释是函数是“实时”编译的,而解释代码不是。请参见
?compiler::enableJIT
了解详细说明。如果要演示差异,请运行
在任何代码之前(* 包括 * 创建
for_loop
函数),这将在该会话的其余部分禁用JIT编译,然后两组代码的时间安排将更加相似。您必须在创建
for_loop
函数之前执行此操作,因为一旦它被JIT编译器编译,它将保持编译状态,无论是否启用JIT。