【发布时间】:2014-08-24 23:30:39
【问题描述】:
我预计Array#shift 和Array#unshift 的运行时间都是Θ(n)。原因是机器需要循环遍历每个数组成员并将其分配给左侧或右侧的键。
在Array#unshift的情况下,假设只有一个值作为参数传入并且有很多数组成员,我假设array[0]的值分配对运行没有显着影响时间。换句话说,当数组成员的数量多而传递给Array#unshift的变量数量少时,我希望Array#shift和Array#unshift具有相同的运行时间。
在 Ruby 2.1.2 上运行基准测试时,这些假设不成立。为什么?
代码:
require 'benchmark'
GC.disable
number_of_elements = 25_600_000
a1 =[]
a2 = []
a3 = []
a4 = []
q1 = Queue.new
q2 = Queue.new
puts number_of_elements
number_of_elements.times do
q1.enq(true)
q2.enq(true)
a1 << true
a2 << true
a3 << true
a4 << true
end
number_of_operations = 1
Benchmark.bm do |bm|
puts "Queue#enq('test')"
bm.report do
number_of_operations.times { q1.enq('test') }
end
puts "Queue#deq"
bm.report do
number_of_operations.times { q2.deq }
end
puts "Array#shift"
bm.report do
number_of_operations.times { a1.shift }
end
puts "Array#unshift"
bm.report do
number_of_operations.times { a2.unshift('test') }
end
puts "Array#pop"
bm.report do
number_of_operations.times { a3.pop }
end
puts "Array#<<"
bm.report do
number_of_operations.times { a4 << 'test' }
end
end
结果:
25600000
user system total real
Queue#enq('test')
0.000000 0.000000 0.000000 ( 0.000006)
Queue#deq
0.010000 0.020000 0.030000 ( 0.029928)
Array#shift
0.010000 0.020000 0.030000 ( 0.032203)
Array#unshift
0.080000 0.060000 0.140000 ( 0.143272)
Array#pop
0.000000 0.000000 0.000000 ( 0.000004)
Array#<<
0.000000 0.000000 0.000000 ( 0.000007)
【问题讨论】:
-
如果增加操作次数会发生什么?
-
#shift@12.8m:0.016307,#shift@25.6m:0.059878,#shift@64m:0.098583,#shift@128m:0.344900。 #unshift@12.8m:0.059736,#unshift@25.6m:0.126382,#unshift@64m:0.285351,#unshift@128m:0.993967。通过仅比较这些比率,似乎#shift 运行在 Θ(3.4n) 和 #unshift 略微指数。
-
您是否研究过 Ruby 源代码以了解数组是如何实现的以及
shift/unshift是如何工作的?幕后可能发生的各种事情都会影响您的结果。将元素添加到数组的开头并不一定会为数组分配一个新条目,它可能会分配很多,或者它可能只是移动一个 array-starts-here 指针;同样,shifting 一个元素可能只是更新一个指向新 index-0 地址的指针。 -
我看了看,但它是用 C 语言编写的,零 C 经验我很难理解。
-
你的问题根本没用,不提你用的是哪个 ruby 版本
标签: ruby arrays performance