更新:
如@ Dave2e所指出的那样,将start_time
语句(在代码2中)移出for
循环将使运行时间与代码1相当。即:
start_time <- Sys.time()
for (j in 1:1) {
n <- 100
result <- 1
for (i in 1:n) {
result <- result * i
}
result
## [1] 9.332622e+157
end_time <- Sys.time()
}
end_time - start_time
for
循环是否真的可以提高性能,还是伪造的?
原始帖子:
我有两段代码,如下所示:
start_time <- Sys.time()
n <- 100
result <- 1
for (i in 1:n) {
result <- result * i
}
result
## [1] 9.332622e+157
end_time <- Sys.time()
end_time - start_time
for (j in 1:1) {
start_time <- Sys.time()
n <- 100
result <- 1
for (i in 1:n){
result <- result * i}
result
## [1] 9.332622e+157
end_time <- Sys.time()
}
end_time - start_time
我期望这两个代码运行类似,但是代码2始终比代码1运行快得多。在我的计算机上,代码1大约需要10 ^ -2秒,而代码2大约需要5 * 10 ^ -6秒。关于如何发生的任何见解?如果仅在整个代码中添加for
循环可以减少程序运行时间,以后我将在所有代码中使用它。
答案 0 :(得分:3)
我认为您的比较不是很可靠。如果不运行多次以获得平均值,就很难说出非常快的代码的相对时序。太多不可控因素会稍微改变运行时间。
我将从下面的基准中得出的结论是,在冗余for循环中封装相当琐碎的计算不会带来很大的伤害,但是任何明显的优势都是琐碎的,可能只是一种效果噪音。
我通过将with_loop
放在每个函数中来封装每个代码块(without_loop
和function() { ... }
)。 (请注意,这意味着我不是基于您的Sys.time()
比较的时间,而是基于microbenchmark
包中的内置时间。)
microbenchmark
软件包更适合基准测试,尤其是对于非常短的计算任务:?microbenchmark::microbenchmark
起:
“微基准”可更精确地替代 通常会看到“ system.time(replicate(1000,expr))”表达式。它 努力准确地仅测量花费的时间 评估“ expr”。为了实现这一目标,亚毫秒级(据说 十亿分之一秒)精确的计时功能,最现代的操作 系统提供使用。此外,对 表达式使用C代码完成,以最大程度地减少开销。
library(microbenchmark)
m1 <- microbenchmark(with_loop, without_loop)
library(ggplot2)
autoplot(m1)+scale_y_log10()
分位数(lq,中位数,uq)实际上是相同的。
Unit: nanoseconds
expr min lq mean median uq max neval cld
with_loop 36 38 48.56 39 40 972 100 a
without_loop 36 39 177.81 40 41 13363 100 a
没有循环的代码确实平均来说要慢 (即,均值更大),但这几乎完全是由几个异常值驱动的。
现在只关注小于50纳秒的值:
autoplot(m1)+scale_y_log10(limits=c(NA,50))
如果我们再次使用times=1e6
(一百万次迭代)执行此操作,则会得到几乎相同的结果:循环的平均值快了3 纳秒(同样可能几乎完全由小驱动上尾巴有波动)。
Unit: nanoseconds
expr min lq mean median uq max neval cld
with_loop 32 39 86.44248 41 61 2474675 1e+06 a
without_loop 35 39 89.86294 41 61 2915836 1e+06 a
如果您需要使循环运行十亿次,则相当于运行时间差了3秒。可能不值得担心。