我用
microbenchmark::microbenchmark()
为两个函数制定了基准,并改变了函数中输入的样本大小。在这样做的过程中,我注意到每次性能时间都会出现一些波动。这是一个简单 while 函数的基准图:
fun <- function(n){
i <- 1
while (n > i) {
i <- i + 1
}
}
x 轴是样本大小 (
n
),以对数刻度表示,y 轴显示中值执行时间。我预计当 n
增加时,运行该函数的时间应该增加,但事实并非如此。我多次运行代码,总是得到相同的图片:存在一些振荡。但为什么呢?
用于生成数据和绘图的完整代码是:
# Load libraries.
library(magrittr)
library(ggplot2)
# Define some function.
fun <- function(n){
i <- 1
while (n > i) {
i <- i + 1
}
}
# Set sample sizes.
n <- c(10, 100, 1000, 10000, 100000, 1000000)
# Run per predefined sample sizes..
results<- lapply(n, function(n_i){
results_i <- microbenchmark::microbenchmark(fun(n= n_i),
times= 1000)
data.frame(n= n_i,
time= summary(results_i)$median)
}) %>%
do.call("rbind.data.frame", .)
# Produce a plot.
results %>%
ggplot(data= ., mapping= aes(x= n, y= time)) +
geom_smooth(se= FALSE) +
geom_point() +
scale_x_continuous(trans='log10') +
theme_minimal()
事实并非如此。您的问题是,当您执行
time = summary(results_i)$median)
时,您正在提取中位时间的数值,但没有考虑时间单位的变化。比较:
microbenchmark::microbenchmark(
fun(n= 1e4),
times= 10
)
# Unit: microseconds
# expr min lq mean median uq max neval
# fun(n = 10000) 959.1 1111.6 1141.56 1150.25 1218.2 1235.1 10
但是,当您将其提高到
1e5
时,您现在看到的是毫秒:
microbenchmark::microbenchmark(
fun(n= 1e5),
times= 10
)
# Unit: milliseconds
# expr min lq mean median uq max neval
# fun(n = 1e+05) 5.9059 6.7059 9.54744 10.2045 11.1353 13.9593 10
您可以重新运行模拟,根据
time
列自行计算中位数,以确保单位相同并获得预期结果:
results <- lapply(
n,
function(n_i) {
microbenchmark::microbenchmark(
fun(n= n_i),
times= 100
) |>
transform(n = n_i)
}) |>
do.call(rbind, args = _)
results |>
dplyr::summarise(
median = median(time),
.by = n
) |>
ggplot(mapping= aes(x= n, y= median)) +
geom_smooth(se = FALSE)
geom_point() +
scale_x_continuous(trans='log10') +
theme_minimal()