我很想知道如何实施sort_by
和sort_by!
。我查看了一些实现代码,但是无法解析大量的宏(这反过来产生了更多的宏)来弄清楚实际发生了什么。
以下是我的基准测试结果:
sort_by -a[:bar] 8.830000 0.010000 8.840000 ( 8.847953)
sort_by a[:bar]*-1 8.620000 0.010000 8.630000 ( 8.628056)
sort_by(&:bar).reverse! 8.550000 0.000000 8.550000 ( 8.558410)
VS
sort_by! -a[:bar] 2.800000 0.000000 2.800000 ( 2.800778)
sort_by! a[:bar]*-1 2.690000 0.000000 2.690000 ( 2.692756)
sort_by!(&:bar).reverse! 2.470000 0.010000 2.480000 ( 2.480710)
我很想知道为什么会有这么大的差异。我有一个假设是sort_by
必须做的内存分配。但这是我的基准测试代码,你可以看到它是一个我正在排序的数组(即分配可以发生一次,数组大小已知)。
#!/usr/bin/ruby
require 'benchmark'
foo = []
for i in 0..10000
foo << {:bar => rand(10000)}
end
Benchmark.bm(20) do |b|
b.report("sort_by! -a[:bar]") { 1000.times { foo.sort_by!{ |a| -a[:bar] } } }
b.report("sort_by! a[:bar]*-1") { 1000.times { foo.sort_by!{ |a| a[:bar]*-1 } } }
b.report("sort_by!(&:bar).reverse!") { 1000.times { foo.sort_by!{ |a| a[:bar] }.reverse! } }
end
答案 0 :(得分:1)
您的基准测试不反映输出,而且需要简化。当你测试时保持简单,只测试你想知道的内容:
require 'benchmark'
BAR = (1..10_000).to_a.shuffle
n = 1000
Benchmark.bmbm(8) do |b|
b.report("sort_by") { n.times { foo = BAR.dup; foo = foo.sort_by{ |a| a }; foo } }
b.report("sort_by!") { n.times { foo = BAR.dup; foo.sort_by!{ |a| a }; foo } }
end
导致:
Rehearsal --------------------------------------------
sort_by 6.350000 0.010000 6.360000 ( 6.364429)
sort_by! 6.620000 0.000000 6.620000 ( 6.615428)
---------------------------------- total: 12.980000sec
user system total real
sort_by 6.350000 0.000000 6.350000 ( 6.353188)
sort_by! 6.840000 0.010000 6.850000 ( 6.842521)
环境可能在您的测试中没有稳定,而且您投入的更改会使测试混乱。
重复所有事情,只有一件事情不同,重要的是测试你想要了解的事情。 sort_by!
改变了数组。 sort_by
返回一个新数组,因此,为了获得相同的结果,您还应该将结果分配给数组。
这个测试值得重复:
require 'benchmark'
BAR = (1..10_000).to_a.shuffle
n = 1000
Benchmark.bmbm(12) do |b|
b.report("sort (no block)") { n.times { foo = BAR.dup; foo = foo.sort; foo } }
b.report("sort! (no block)") { n.times { foo = BAR.dup; foo.sort!; foo } }
b.report("sort (block)") { n.times { foo = BAR.dup; foo = foo.sort{ |a, b| a <=> b }; foo } }
b.report("sort! (block)") { n.times { foo = BAR.dup; foo.sort!{ |a, b| a <=> b }; foo } }
b.report("sort_by") { n.times { foo = BAR.dup; foo = foo.sort_by{ |a| a }; foo } }
b.report("sort_by!") { n.times { foo = BAR.dup; foo.sort_by!{ |a| a }; foo } }
end
导致:
Rehearsal ----------------------------------------------------
sort (no block) 1.250000 0.010000 1.260000 ( 1.253412)
sort! (no block) 1.240000 0.010000 1.250000 ( 1.254230)
sort (block) 12.380000 0.010000 12.390000 ( 12.378503)
sort! (block) 12.390000 0.000000 12.390000 ( 12.399870)
sort_by 6.410000 0.010000 6.420000 ( 6.408380)
sort_by! 6.720000 0.000000 6.720000 ( 6.727324)
------------------------------------------ total: 40.430000sec
user system total real
sort (no block) 1.240000 0.010000 1.250000 ( 1.249624)
sort! (no block) 1.230000 0.020000 1.250000 ( 1.241353)
sort (block) 12.320000 0.010000 12.330000 ( 12.341552)
sort! (block) 12.390000 0.010000 12.400000 ( 12.397626)
sort_by 6.410000 0.010000 6.420000 ( 6.411413)
sort_by! 6.940000 0.000000 6.940000 ( 6.943647)
这有两个“外卖”:
sort
outruns sort_by
,如果可以,请使用sort
系列而不使用阻止。sort_by
系列。答案 1 :(得分:0)
我在这里猜测:sort_by!
在Array上定义,因此可以针对数组进行优化,而sort_by
在Enumerable上定义,因此它必须能够处理各种类型的枚举。 / p>