这两种形式的数组初始化中哪一种在Ruby中更好?
方法1:
DAYS_IN_A_WEEK = (0..6).to_a
HOURS_IN_A_DAY = (0..23).to_a
@data = Array.new(DAYS_IN_A_WEEK.size).map!{ Array.new(HOURS_IN_A_DAY.size) }
DAYS_IN_A_WEEK.each do |day|
HOURS_IN_A_DAY.each do |hour|
@data[day][hour] = 'something'
end
end
方法2:
DAYS_IN_A_WEEK = (0..6).to_a
HOURS_IN_A_DAY = (0..23).to_a
@data = {}
DAYS_IN_A_WEEK.each do |day|
HOURS_IN_A_DAY.each do |hour|
@data[day] ||= {}
@data[day][hour] = 'something'
end
end
第一种方法和第二种方法的区别在于第二种方法最初不分配内存。我觉得第二个在性能方面有点逊色,因为必须发生大量的阵列拷贝。
然而,在Ruby中找不到正在发生的事情并不是直截了当的。所以,如果有人能解释我哪个更好,那真的很棒!
由于
答案 0 :(得分:3)
在我回答你提出的问题之前,我将回答你应该问的问题但是没有:
问:我应该首先专注于使我的代码可读,还是应该首先关注性能?
A:首先使您的代码可以正确,然后 如果出现性能问题,请开始担心性能通过衡量,性能问题优先,只有然后对代码进行更改。
现在回答你提出的问题,但不应该:
method1.rb:
DAYS_IN_A_WEEK = (0..6).to_a
HOURS_IN_A_DAY = (0..23).to_a
10000.times do
@data = Array.new(DAYS_IN_A_WEEK.size).map!{ Array.new(HOURS_IN_A_DAY.size) }
DAYS_IN_A_WEEK.each do |day|
HOURS_IN_A_DAY.each do |hour|
@data[day][hour] = 'something'
end
end
end
method2.rb:
DAYS_IN_A_WEEK = (0..6).to_a
HOURS_IN_A_DAY = (0..23).to_a
10000.times do
@data = {}
DAYS_IN_A_WEEK.each do |day|
HOURS_IN_A_DAY.each do |hour|
@data[day] ||= {}
@data[day][hour] = 'something'
end
end
end
脑死亡基准的结果:
$ time ruby method1.rb
real 0m1.189s
user 0m1.140s
sys 0m0.000s
$ time ruby method2.rb
real 0m1.879s
user 0m1.780s
sys 0m0.020s
在我看来,用户时间使用(重要因素)使method1.rb快得多。当然,您不应该信任此基准测试,并且应该自己反映您的实际代码使用情况。但是,这是你应该只做后确定哪些代码是你现实中的性能瓶颈。 (提示:99.44%的计算机程序员100%错误当他们猜测他们的瓶颈在哪里而没有测量!)
答案 1 :(得分:3)
只是
有什么问题@data = Array.new(7) { Array.new(24) { 'something' }}
或者,如果您满足于相同的对象:
@data = Array.new(7) { Array.new(24, 'something') }
速度快得多,而不是重要。它还更多可读,这是最重要的事情。毕竟,代码的目的是向其他利益相关者传达意图,不与计算机进行通信。
user system total real method1 8.969000 0.000000 8.969000 ( 9.059570) method2 16.547000 0.000000 16.547000 (16.799805) method3 6.468000 0.000000 6.468000 ( 6.616211) method4 0.969000 0.015000 0.984000 ( 1.021484)最后一行也显示了另一个有趣的事情:运行时占主导地位创建7 * 24 * 100000 = 1680万
'something'
字符串所需的时间。
当然还有另一个重要的观点:你正在比较的method1
和method2
会做两件完全不同的事情!将它们相互比较甚至没有意义。 method1
创建Array
,method2
创建Hash
。
您的method1
等同于我上面的第一个示例:
@data = Array.new(7) { Array.new(24) { 'something' }}
虽然method2
(非常大致)相当于:
@data = Hash.new {|h, k| h[k] = Hash.new {|h, k| h[k] = 'something' }}
好吧,除了你的 method2
急切地初始化整个Hash
,而我的方法只是在读取未初始化的密钥时懒惰地执行初始化代码。
换句话说,在运行上述初始化代码后,Hash
仍为空:
@data # => {}
但无论何时尝试访问密钥,它都会神奇地出现:
@data[5][17] # => 'something'
它会留在那里:
@data # => {5 => {17 => 'something'}}
由于此代码实际上并未初始化Hash
,因此显然会更快:
user system total real method5 0.266000 0.000000 0.266000 ( 0.296875)
答案 2 :(得分:2)
我将两个代码片段包装成单独的方法并进行了一些基准测试。结果如下:
Benchmark.bm(7) do |x|
x.report ("method1") { 100000.times { method1 } }
x.report ("method2") { 100000.times { method2 } }
end
user system total real
method1 11.370000 0.010000 11.380000 ( 11.392233)
method2 17.920000 0.010000 17.930000 ( 18.328318)