测量性能
Benchmark 模块
测量性能 是 CoddyKit 上的免费 Ruby Academy 课时。 这是第 1 节课,共 4 节。 你可以在下方免费阅读本课时的完整内容 — 然后在浏览器中使用内置代码编辑器和全天候 AI 导师进行实践。 这是 Ruby Academy 学习路径的一部分,你的进度在网页和 CoddyKit 应用中同步。 Ruby Academy 课程共包含 4 节课。
为什么要测量?
不进行测量就优化,等同于猜测。Ruby 标准库中的 Benchmark 模块可以精确地为代码计时。
- 在修改之前找出速度较慢的部分
- 客观地比较不同实现
- 避免过早优化
require 'benchmark'
time = Benchmark.realtime do
1_000_000.times { |i| i * 2 }
end
puts "Took #{time.round(4)}s"Benchmark.measure
Benchmark.measure 返回包含用户时间、系统时间和实际时间的 report。
- 用户时间是代码消耗的 CPU 时间
- 实际时间是挂钟经过的时间
require 'benchmark'
result = Benchmark.measure do
500_000.times { |i| i.to_s }
end
puts resultBenchmark.bm
Benchmark.bm 在表格中运行多个代码块并为其添加标签。
- 传入标签宽度以便对齐
- 每个
x.report都是一行
require 'benchmark'
Benchmark.bm(10) do |x|
x.report('to_s:') { 100_000.times { |i| i.to_s } }
x.report('inspect:') { 100_000.times { |i| i.inspect } }
endBenchmark.bmbm
Benchmark.bmbm 会先运行一次预演,以预热缓存和垃圾回收器,从而得到更公平的数值。
- 第一次运行的结果会被丢弃
- 第二次运行才是真正的测量
require 'benchmark'
Benchmark.bmbm do |x|
x.report('sum:') { (1..100_000).sum }
x.report('reduce:') { (1..100_000).reduce(:+) }
end用于快速计时的 realtime
Benchmark.realtime 只返回以浮点数表示的挂钟秒数。
- 为一个代码块计时的最简单方式
- 适合临时检查
require 'benchmark'
elapsed = Benchmark.realtime do
arr = Array.new(100_000) { rand }
arr.sort
end
puts "Sorted in #{elapsed.round(4)}s"单调时钟
如果需要不受系统时钟变化影响的精确计时,请将 Process.clock_gettime 与单调时钟结合使用。
- 不受 NTP 调整影响
- 最准确的内置选项
start = Process.clock_gettime(Process::CLOCK_MONOTONIC)
200_000.times { |i| i * i }
finish = Process.clock_gettime(Process::CLOCK_MONOTONIC)
puts "Elapsed: #{(finish - start).round(4)}s"比较两种方法
比较不同方案时,基准测试最能发挥作用。请在相同的负载下运行两种方案。
- 保持足够大的输入规模,以便测量
- 重复运行以减少噪声
require 'benchmark'
arr = (1..100_000).to_a
Benchmark.bm(8) do |x|
x.report('map:') { arr.map { |n| n * 2 } }
x.report('each:') { r = []; arr.each { |n| r << n * 2 } }
end警惕微型基准测试
微型基准测试可能会误导您。
- 即时编译和缓存可能无法反映真实工作负载
- 垃圾回收器可能在测量过程中运行
- 请测量符合实际的数据规模
require 'benchmark'
# Too small to be meaningful
t = Benchmark.realtime { 10.times { |i| i + 1 } }
puts "Misleadingly tiny: #{t}s"每秒迭代次数
您通常会关注吞吐量,也就是每秒可以执行多少次操作。benchmark-ips gem 会报告这一指标,但您也可以手动进行近似计算。
- 在固定的时间窗口内统计迭代次数
- 每秒迭代次数越高,速度越快
deadline = Process.clock_gettime(Process::CLOCK_MONOTONIC) + 0.2
count = 0
while Process.clock_gettime(Process::CLOCK_MONOTONIC) < deadline
count += 1
'hello'.upcase
end
puts "Iterations in 0.2s: #{count}"控制垃圾回收器
垃圾回收器可能会使结果产生偏差。您可以暂时禁用它,以获得更稳定的数值。
- 之前使用
GC.disable,之后使用GC.enable - 请谨慎使用,以免内存持续增长
require 'benchmark'
GC.disable
t = Benchmark.realtime { 100_000.times { |i| i.to_s } }
GC.enable
puts "Without GC: #{t.round(4)}s"对多次运行取平均值
多次运行基准测试并取平均值,可以平滑差异。
- 如有需要,丢弃最慢的离群值
- 报告中位数以提高稳定性
require 'benchmark'
times = 3.times.map do
Benchmark.realtime { (1..50_000).map { |n| n * n } }
end
avg = times.sum / times.size
puts "Average: #{avg.round(4)}s"快速检查
测试您对基准测试的了解。
回顾
您学会了测量性能:
Benchmark模块可以准确地为代码计时realtime、measure、bm和bmbm适用于不同需求- 使用单调时钟进行精确计时
- 避免会产生误导的微型基准测试,并考虑垃圾回收器的影响
- 对多次运行取平均值,以减少噪声
接下来您将使用专门的性能分析工具。
常见问题解答
「测量性能」课时是免费的吗?
是的 — 「测量性能」的完整文本可在网页上免费阅读。要进行交互式练习(内置代码编辑器和全天候 AI 导师)并解锁 Ruby Academy 课程的其余内容,请升级到 CoddyKit PRO。 Ruby Academy 课程共包含 4 节课。
「测量性能」这节课中我会学到什么?
Benchmark 模块 你通过在浏览器中直接运行的动手代码来练习 Ruby Academy,全天候 AI 导师会在你学习这节课的过程中回答你的问题。
学习 Ruby Academy 需要有经验吗?
无需任何先前经验。CoddyKit 上的 Ruby Academy 课程适合初学者到高级学习者,你可以从这里开始或从头开始,按照自己的节奏学习。 这是第 1 节课,共 4 节。
「测量性能」课时需要多长时间?
大多数 CoddyKit 课程大约需要 5–10 分钟。每节课都很精短且互动,所以你能稳步进步,并在网页和应用中从离开的地方继续。
我能在这节 Ruby Academy 课中编写并运行代码吗?
能。每节 Ruby Academy 课都包含内置代码编辑器,你可以在浏览器中直接编写并运行真实代码,并获得即时 AI 反馈 — 无需本地设置。