为何增大样本量时microbenchmark基准测试结果出现振荡?
基准测试耗时出现振荡现象的原因?
我用microbenchmark::microbenchmark()对两个函数做基准测试,还调整了输入样本量,结果发现性能耗时每次都有振荡。下面是一个简单while函数的测试情况:
fun <- function(n){ i <- 1 while (n > i) { i <- i + 1 } }

图中x轴是对数刻度的样本量n,y轴是中位数性能耗时。我本来以为函数运行时间会随n增大而增加,但实际不是这样,多次运行代码都得到相同的振荡结果。这是为什么?
生成数据和绘图的完整代码如下:
# 加载依赖包 library(magrittr) library(ggplot2) # 定义测试函数 fun <- function(n){ i <- 1 while (n > i) { i <- i + 1 } } # 设置样本量 n <- c(10, 100, 1000, 10000, 100000, 1000000) # 批量运行基准测试 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", .) # 绘制结果图 results %>% ggplot(data= ., mapping= aes(x= n, y= time)) + geom_smooth(se= FALSE) + geom_point() + scale_x_continuous(trans='log10') + theme_minimal()
原因分析
这种振荡现象主要和CPU分支预测机制以及微基准测试的噪声特性有关:
- 分支预测的波动:你的
while循环核心是n > i这个条件判断。CPU会通过分支预测提前预判循环是否继续,当迭代次数符合预测规律时(比如n为特定值),预测准确率极高,耗时大幅降低;一旦迭代次数打破预测模式,分支预测误判率上升,单次循环耗时会突然增加,最终表现为整体耗时的振荡。 - 微基准测试的噪声放大:
microbenchmark虽然能精确测量短耗时,但系统层面的干扰(进程调度、缓存命中/失效、CPU动态调频)在测试极短函数时会被放大。你的fun本身执行时间极短,哪怕是毫秒级的系统波动都会让结果出现明显振荡。 - 小样本量的误差放大:当
n较小时,循环迭代次数少,单次迭代的耗时占比更高,任何微小的执行差异都会被放大,导致结果波动更显著。
优化建议
- 增加测试次数:将
times参数调至更大值(比如times=10000),取多次测试的均值或中位数,能有效降低随机噪声的影响,让线性趋势更清晰。 - 固定测试环境:关闭后台无关进程,避免资源竞争;如果是多核CPU,可将测试进程绑定到单个核心(Linux用
taskset,Windows用Start-Process -Affinity),减少进程调度带来的干扰。 - 调整函数逻辑:把
while循环改为for循环,因为for循环的迭代次数提前确定,CPU分支预测的准确率更高,耗时随n增长会更接近线性:fun_for <- function(n){ for(i in 1:n) {} }
内容的提问来源于stack exchange,提问作者LulY
相关产品推荐
相关产品推荐

