r - 为什么循环计算更快?
问题描述
更新:
正如@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
循环真的提高了性能还是假的?
原帖:
我有两段代码如下:
代码 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:
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
在整个代码中添加循环可以减少程序运行时间,那么我将来会在我的所有代码中使用它。
解决方案
我认为您的比较不是很可靠。如果不多次运行以获得平均值,就很难说出非常快的代码的相对时间 - 太多的不可控因素会稍微改变运行时间。
我从下面的基准测试中得出的结论是,在冗余 for 循环中封装一个相当微不足道的计算并没有太大的伤害,但任何明显的优势都是微不足道的,可能只是噪音的影响。
我通过将每个代码块封装在一个函数 ( with_loop
and without_loop
)function() { ... }
中。(请注意,这意味着我的时间不是基于您的Sys.time()
比较,而是基于包中的内置时间microbenchmark
。)
该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 秒差异。可能不值得担心。
推荐阅读
- google-cloud-platform - GCP IAM 用户删除日志
- firebase - 如何编写查询firebase
- reactjs - 如何使用 Axios 发送表单数据并做出原生反应?
- python - WA bot 中的多级菜单,每个级别都有相同的数字。我怎样才能做到这一点
- flutter - 如何在 Dart / Flutter pdf 库中使用 drawBox、drawEllipse 或 drawLine 方法
- c++ - unscoped-enum 的显式 ctor 及其底层类型
- java - Java compare.comparing(o->x).reversed 不起作用
- javascript - 是否可以批量更改 slickgrid 中分组行的单元格值?
- python - 浮点数列表之间的相似性
- reactjs - 连接路由器打字稿声明全局状态类型