非常教程

Ruby 2.4参考手册

基准测试 | Benchmark

Benchmark

Benchmark模块提供了测量和报告执行Ruby代码所用时间的方法。

  • 测量时间来构造表达式给出的字符串"a"*1_000_000_000:require'benchmark'puts Benchmark.measure {“a”* 1_000_000_000}在我的机器上(iX 1.7 GHz上的OSX 10.8.3)产生:0.350000 0.400000 0.750000(0.835234)This报告显示用户CPU时间,系统CPU时间,用户和系统CPU时间总和以及实时实际时间。时间单位是秒。
  • 使用bm方法按顺序进行一些实验:

require 'benchmark' n = 5000000 Benchmark.bm do |x| x.report { for i in 1..n; a = "1"; end } x.report { n.times do ; a = "1"; end } x.report { 1.upto(n) do ; a = "1"; end } end

结果:

 user     system      total        real 1.010000   0.000000   1.010000 (  1.014479) 1.000000   0.000000   1.000000 (  0.998261) 0.980000   0.000000   0.980000 (  0.981335)
  • 继续前面的例子,在每个报告中加上一个标签:require'benchmark'n = 5000000 Benchmark.bm(7)do | x | x.report(“for:”){for i in 1..n; a =“1”; end} x.report(“times:”){n.times do; a =“1”; end} x.report(“upto:”){1.upto(n)do; a =“1”; end} end结果:用户系统实际总数为:1.010000 0.000000 1.010000(1.015688)次:1.000000 0.000000 1.000000(1.003611)upto:1.030000 0.000000 1.030000(1.028098)
  • 某些基准测试的时间取决于项目的运行顺序。这些差异是由于内存分配和垃圾收集的成本。为了避免这些差异,提供了bmbm方法。例如,要比较排序浮点数组的方法:

require 'benchmark' array = (1..1000000).map { rand } Benchmark.bmbm do |x| x.report("sort!") { array.dup.sort! } x.report("sort") { array.dup.sort } end

结果:

Rehearsal ----------------------------------------- sort! 1.490000 0.010000 1.500000 ( 1.490520) sort 1.460000 0.000000 1.460000 ( 1.463025) -------------------------------- total: 2.960000sec user system total real sort! 1.460000 0.000000 1.460000 ( 1.460465) sort 1.450000 0.010000 1.460000 ( 1.448327)

  • 使用基准方法报告具有独特标签的连续实验的统计数据:

require 'benchmark' include Benchmark # we need the CAPTION and FORMAT constants n = 5000000 Benchmark.benchmark(CAPTION, 7, FORMAT, ">total:", ">avg:") do |x| tf = x.report("for:") { for i in 1..n; a = "1"; end } tt = x.report("times:") { n.times do ; a = "1"; end } tu = x.report("upto:") { 1.upto(n) do ; a = "1"; end } tf+tt+tu, (tf+tt+tu)/3 end

结果:

          user     system      total        real for:      0.950000   0.000000   0.950000 (  0.952039) times:    0.980000   0.000000   0.980000 (  0.984938) upto:     0.950000   0.000000   0.950000 (  0.946787) >total:   2.880000   0.000000   2.880000 (  2.883764) >avg:     0.960000   0.000000   0.960000 (  0.961255)

常量

CAPTION

默认标题字符串(标题高于输出时间)。

FORMAT

用于显示时间的默认格式字符串。另见Benchmark :: Tms#格式。

公共类方法

benchmark(caption = "", label_width = nil, format = nil, *labels) { |report| ... } Show source

使用Benchmark :: Report对象调用该块,该对象可用于收集和报告单个基准测试的结果。label_width为每条生产线上的标签预留空间。打印caption在报告的顶部,format用于格式化每一行。返回Benchmark :: Tms对象的数组。

如果该块返回一个Benchmark :: Tms对象的数组,则这些将用于格式化额外的输出行。如果labels给出参数,则用这些参数标记这些额外的行。

:其他方法提供了一个更简单的接口,适用于几乎所有的基准测试要求。请参阅Benchmark中的示例以及bm和bmbm方法。

例:

require 'benchmark'
include Benchmark          # we need the CAPTION and FORMAT constants

n = 5000000
Benchmark.benchmark(CAPTION, 7, FORMAT, ">total:", ">avg:") do |x|
  tf = x.report("for:")   { for i in 1..n; a = "1"; end }
  tt = x.report("times:") { n.times do   ; a = "1"; end }
  tu = x.report("upto:")  { 1.upto(n) do ; a = "1"; end }
  [tf+tt+tu, (tf+tt+tu)/3]
end

产生:

              user     system      total        real
for:      0.970000   0.000000   0.970000 (  0.970493)
times:    0.990000   0.000000   0.990000 (  0.989542)
upto:     0.970000   0.000000   0.970000 (  0.972854)
>total:   2.930000   0.000000   2.930000 (  2.932889)
>avg:     0.976667   0.000000   0.976667 (  0.977630)
# File lib/benchmark.rb, line 164
def benchmark(caption = "", label_width = nil, format = nil, *labels) # :yield: report
  sync = STDOUT.sync
  STDOUT.sync = true
  label_width ||= 0
  label_width += 1
  format ||= FORMAT
  print ' '*label_width + caption unless caption.empty?
  report = Report.new(label_width, format)
  results = yield(report)
  Array === results and results.grep(Tms).each {|t|
    print((labels.shift || t.label || "").ljust(label_width), t.format(format))
  }
  report.list
ensure
  STDOUT.sync = sync unless sync.nil?
end

bm(label_width = 0, *labels) { |report| ... } Show source

一个简单的基准方法接口,bm生成带有标签的连续报告。label_widthlabels参数的含义为基准相同。

require 'benchmark'

n = 5000000
Benchmark.bm(7) do |x|
  x.report("for:")   { for i in 1..n; a = "1"; end }
  x.report("times:") { n.times do   ; a = "1"; end }
  x.report("upto:")  { 1.upto(n) do ; a = "1"; end }
end

产生:

              user     system      total        real
for:      0.960000   0.000000   0.960000 (  0.957966)
times:    0.960000   0.000000   0.960000 (  0.960423)
upto:     0.950000   0.000000   0.950000 (  0.954864)
# File lib/benchmark.rb, line 203
def bm(label_width = 0, *labels, &blk) # :yield: report
  benchmark(CAPTION, label_width, FORMAT, *labels, &blk)
end

bmbm(width = 0) { |job| ... } Show source

有时候基准测试结果有偏差,因为之前执行的代码遇到不同于以后运行的垃圾收集开销。bmbm尝试通过两次运行测试来最小化这种影响,第一次作为排练以便使运行时环境稳定,第二次是真实的。GC.start在每个实时定时开始之前执行; 这个时间的成本不包括在内。但实际上,bmbm只能做到这一点,而且结果不能保证与垃圾收集和其他效果隔离。

由于bmbm需要两次通过测试,它可以计算所需的标签宽度。

require 'benchmark'

array = (1..1000000).map { rand }

Benchmark.bmbm do |x|
  x.report("sort!") { array.dup.sort! }
  x.report("sort")  { array.dup.sort  }
end

产生:

Rehearsal -----------------------------------------
sort!   1.440000   0.010000   1.450000 (  1.446833)
sort    1.440000   0.000000   1.440000 (  1.448257)
-------------------------------- total: 2.890000sec

            user     system      total        real
sort!   1.460000   0.000000   1.460000 (  1.458065)
sort    1.450000   0.000000   1.450000 (  1.455963)

bmbm产生一个Benchmark :: Job对象并返回一个Benchmark :: Tms对象的数组。

# File lib/benchmark.rb, line 245
def bmbm(width = 0) # :yield: job
  job = Job.new(width)
  yield(job)
  width = job.width + 1
  sync = STDOUT.sync
  STDOUT.sync = true

  # rehearsal
  puts 'Rehearsal '.ljust(width+CAPTION.length,'-')
  ets = job.list.inject(Tms.new) { |sum,(label,item)|
    print label.ljust(width)
    res = Benchmark.measure(&item)
    print res.format
    sum + res
  }.format("total: %tsec")
  print " #{ets}\n\n".rjust(width+CAPTION.length+2,'-')

  # take
  print ' '*width + CAPTION
  job.list.map { |label,item|
    GC.start
    print label.ljust(width)
    Benchmark.measure(label, &item).tap { |res| print res }
  }
ensure
  STDOUT.sync = sync unless sync.nil?
end

measure(label = "") { || ... } Show source

将用于执行给定块的时间作为Benchmark :: Tms对象返回。注意到label选项。

require 'benchmark'

n = 1000000

time = Benchmark.measure do
  n.times { a = "1" }
end
puts time

产生:

0.220000   0.000000   0.220000 (  0.227313)
# File lib/benchmark.rb, line 290
def measure(label = "") # :yield:
  t0, r0 = Process.times, Process.clock_gettime(Process::CLOCK_MONOTONIC)
  yield
  t1, r1 = Process.times, Process.clock_gettime(Process::CLOCK_MONOTONIC)
  Benchmark::Tms.new(t1.utime  - t0.utime,
                     t1.stime  - t0.stime,
                     t1.cutime - t0.cutime,
                     t1.cstime - t0.cstime,
                     r1 - r0,
                     label)
end

realtime() { || ... } Show source

返回用于执行给定块的已用实时时间。

# File lib/benchmark.rb, line 305
def realtime # :yield:
  r0 = Process.clock_gettime(Process::CLOCK_MONOTONIC)
  yield
  Process.clock_gettime(Process::CLOCK_MONOTONIC) - r0
end

私有实例方法

benchmark(caption = "", label_width = nil, format = nil, *labels) { |report| ... } Show source

使用Benchmark :: Report对象调用该块,该对象可用于收集和报告单个基准测试的结果。 为每行上的标签保留label_width前导空格。 在报告的顶部打印标题,并使用格式来格式化每一行。 返回Benchmark :: Tms对象的数组。

如果该块返回一个Benchmark :: Tms对象的数组,则这些将用于格式化额外的输出行。如果labels给出参数,则用这些参数标记这些额外的行。

:其他方法提供了一个更简单的接口,适用于几乎所有的基准测试要求。请参阅Benchmark中的示例以及bm和bmbm方法。

例:

require 'benchmark'
include Benchmark          # we need the CAPTION and FORMAT constants

n = 5000000
Benchmark.benchmark(CAPTION, 7, FORMAT, ">total:", ">avg:") do |x|
  tf = x.report("for:")   { for i in 1..n; a = "1"; end }
  tt = x.report("times:") { n.times do   ; a = "1"; end }
  tu = x.report("upto:")  { 1.upto(n) do ; a = "1"; end }
  [tf+tt+tu, (tf+tt+tu)/3]
end

产生:

              user     system      total        real
for:      0.970000   0.000000   0.970000 (  0.970493)
times:    0.990000   0.000000   0.990000 (  0.989542)
upto:     0.970000   0.000000   0.970000 (  0.972854)
>total:   2.930000   0.000000   2.930000 (  2.932889)
>avg:     0.976667   0.000000   0.976667 (  0.977630)
# File lib/benchmark.rb, line 164
def benchmark(caption = "", label_width = nil, format = nil, *labels) # :yield: report
  sync = STDOUT.sync
  STDOUT.sync = true
  label_width ||= 0
  label_width += 1
  format ||= FORMAT
  print ' '*label_width + caption unless caption.empty?
  report = Report.new(label_width, format)
  results = yield(report)
  Array === results and results.grep(Tms).each {|t|
    print((labels.shift || t.label || "").ljust(label_width), t.format(format))
  }
  report.list
ensure
  STDOUT.sync = sync unless sync.nil?
end

bm(label_width = 0, *labels) { |report| ... } Show source

一个简单的基准方法接口,bm生成带有标签的连续报告。label_widthlabels参数的含义为基准相同。

require 'benchmark'

n = 5000000
Benchmark.bm(7) do |x|
  x.report("for:")   { for i in 1..n; a = "1"; end }
  x.report("times:") { n.times do   ; a = "1"; end }
  x.report("upto:")  { 1.upto(n) do ; a = "1"; end }
end

产生:

              user     system      total        real
for:      0.960000   0.000000   0.960000 (  0.957966)
times:    0.960000   0.000000   0.960000 (  0.960423)
upto:     0.950000   0.000000   0.950000 (  0.954864)
# File lib/benchmark.rb, line 203
def bm(label_width = 0, *labels, &blk) # :yield: report
  benchmark(CAPTION, label_width, FORMAT, *labels, &blk)
end

bmbm(width = 0) { |job| ... } Show source

有时候基准测试结果有偏差,因为之前执行的代码遇到不同于以后运行的垃圾收集开销。bmbm尝试通过两次运行测试来最小化这种影响,第一次作为排练以便使运行时环境稳定,第二次是真实的。GC.start在每个实时定时开始之前执行; 这个时间的成本不包括在内。但实际上,bmbm只能做到这一点,而且结果不能保证与垃圾收集和其他效果隔离。

由于bmbm需要两次通过测试,它可以计算所需的标签宽度。

require 'benchmark'

array = (1..1000000).map { rand }

Benchmark.bmbm do |x|
  x.report("sort!") { array.dup.sort! }
  x.report("sort")  { array.dup.sort  }
end

产生:

Rehearsal -----------------------------------------
sort!   1.440000   0.010000   1.450000 (  1.446833)
sort    1.440000   0.000000   1.440000 (  1.448257)
-------------------------------- total: 2.890000sec

            user     system      total        real
sort!   1.460000   0.000000   1.460000 (  1.458065)
sort    1.450000   0.000000   1.450000 (  1.455963)

bmbm产生一个Benchmark :: Job对象并返回一个Benchmark :: Tms对象的数组。

# File lib/benchmark.rb, line 245
def bmbm(width = 0) # :yield: job
  job = Job.new(width)
  yield(job)
  width = job.width + 1
  sync = STDOUT.sync
  STDOUT.sync = true

  # rehearsal
  puts 'Rehearsal '.ljust(width+CAPTION.length,'-')
  ets = job.list.inject(Tms.new) { |sum,(label,item)|
    print label.ljust(width)
    res = Benchmark.measure(&item)
    print res.format
    sum + res
  }.format("total: %tsec")
  print " #{ets}\n\n".rjust(width+CAPTION.length+2,'-')

  # take
  print ' '*width + CAPTION
  job.list.map { |label,item|
    GC.start
    print label.ljust(width)
    Benchmark.measure(label, &item).tap { |res| print res }
  }
ensure
  STDOUT.sync = sync unless sync.nil?
end

measure(label = "") { || ... } Show source

将用于执行给定块的时间作为Benchmark :: Tms对象返回。注意到label选项。

require 'benchmark'

n = 1000000

time = Benchmark.measure do
  n.times { a = "1" }
end
puts time

产生:

0.220000   0.000000   0.220000 (  0.227313)
# File lib/benchmark.rb, line 290
def measure(label = "") # :yield:
  t0, r0 = Process.times, Process.clock_gettime(Process::CLOCK_MONOTONIC)
  yield
  t1, r1 = Process.times, Process.clock_gettime(Process::CLOCK_MONOTONIC)
  Benchmark::Tms.new(t1.utime  - t0.utime,
                     t1.stime  - t0.stime,
                     t1.cutime - t0.cutime,
                     t1.cstime - t0.cstime,
                     r1 - r0,
                     label)
end

realtime() { || ... } Show source

返回用于执行给定块的已用实时时间。

# File lib/benchmark.rb, line 305
def realtime # :yield:
  r0 = Process.clock_gettime(Process::CLOCK_MONOTONIC)
  yield
  Process.clock_gettime(Process::CLOCK_MONOTONIC) - r0
end

基准测试 | Benchmark相关

Ruby 2.4

Ruby 是一种面向对象、命令式、函数式、动态的通用编程语言,是世界上最优美而巧妙的语言。

主页 https://www.ruby-lang.org/
源码 https://github.com/ruby/ruby
版本 2.4
发布版本 2.4.1

Ruby 2.4目录

1.缩略 | Abbrev
2.ARGF
3.数组 | Array
4.Base64
5.基本对象 | BasicObject
6.基准测试 | Benchmark
7.BigDecimal
8.绑定 | Binding
9.CGI
10.类 | Class
11.比较 | Comparable
12.负责 | Complex
13.计算续体 | Continuation
14.覆盖 | Coverage
15.CSV
16.日期 | Date
17.日期时间 | DateTime
18.DBM
19.代理 | Delegator
20.摘要 | Digest
21.Dir
22.DRb
23.编码 | Encoding
24.枚举 | Enumerable
25.枚举 | Enumerator
26.ENV
27.ERB
28.错误 | Errors
29.Etc
30.期望值 | Exception
31.错误类 | FalseClass
32.Fiber
33.Fiddle
34.文件 | File
35.文件实用程序 | FileUtils
36.查找 | Find
37.浮点 | Float
38.Forwardable
39.GC
40.GDBM
41.GetoptLong
42.Hash
43.Integer
44.IO
45.IPAddr
46.JSON
47.Kernel
48.语言 | 3Language
49.记录 | Logger
50.编排 | Marshal
51.MatchData
52.数学 | Math
53.矩阵 | Matrix
54.方法 | Method
55.模型 | Module
56.监控 | Monitor
57. 互斥 | Mutex
58.Net
59.Net::FTP
60.Net::HTTP
61.Net::IMAP
62.Net::SMTP
63.NilClass
64.数字 | Numeric
65.对象 | Object
66.ObjectSpace
67.Observable
68.Open3
69.OpenSSL
70.OpenStruct
71.OpenURI
72.OptionParser
73.路径名 | Pathname
74.完整输出 | PrettyPrint
75.Prime
76.Proc
77.过程 | Process
78.PStore
79.PTY
80.队列 | Queue
81.随机 | Random
82.范围 | Range
83.合理的 | Rational
84.Readline
85.Regexp
86.Resolv
87.Ripper
88.RubyVM
89.Scanf
90.SDBM
91.SecureRandom
92.Set
93.Shell
94.信号 | Signal
95.Singleton
96.套接字 | Socket
97.字符串 | String
98.StringIO
99.StringScanner
100.结构 | Struct