Ruby 2.2.0 比 2.1.5 慢
Mashalling in Ruby 2.2.0 slower than 2.1.5
我有一个复杂的对象,my_object,我用它编组
Marshal.dump(my_object)
我已经在 2.1.5p273 和 2.2.0 中对调用该行 100 次的性能进行了基准测试,结果如下:
2.1.5
user system total real
Marshal Dump 7.310000 0.120000 7.430000 ( 8.988470)
Marshal Dump 7.520000 0.050000 7.570000 ( 8.210356)
Marshal Dump 7.610000 0.050000 7.660000 ( 8.432685)
2.2.0
user system total real
Marshal Dump 26.480000 0.150000 26.630000 ( 29.591742)
Marshal Dump 24.100000 0.300000 24.400000 ( 28.520397)
Marshal Dump 26.210000 0.210000 26.420000 ( 29.993412)
(我运行每个版本做3次benchmark,要彻底。)
如您所见,2.2.0 与 2.1.5 相比花费了 3 倍多的时间。我将注意力集中在 Marshal.dump 上,因为使用 ruby-prof gem,它告诉我那条线表现不佳;但我找不到获取 Marshal.dump 本身在分析器中调用的方法的方法。
编辑:经过大量实验后找到了我的答案,经过最少的复现
来源位置是nil
。
Marshal.method(:dump).source_location
#=> nil
这意味着它是一个 C 实现的方法,并且没有更多的 Ruby 代码可以跟踪。换句话说,它是一个atomic/elementary方法。
如果您认为您的结果是有效的,那么我建议您 post 将其作为 Ruby trunk 中的错误。 Ruby 的最新版本确实发现了几个性能问题,因此您的情况似乎并不罕见。
编组浮点数导致减速。
require 'benchmark'
class ToBeMarshaled
def initialize n
@a = []
n.times do |i|
@a << i.to_f
end
end
end
tbm = ToBeMarshaled.new(10000)
n = 100
Benchmark.bm do |x|
x.report("Marshal Dump") {for i in 1..n; Marshal.dump(tbm); end}
end
结果(运行 每个 Ruby 版本基准测试 3 次):
2.1.5
user system total real
Marshal Dump 0.640000 0.010000 0.650000 ( 0.744080)
Marshal Dump 0.670000 0.000000 0.670000 ( 0.758597)
Marshal Dump 0.650000 0.020000 0.670000 ( 0.747583)
2.2.0
user system total real
Marshal Dump 25.070000 0.220000 25.290000 ( 27.980023)
Marshal Dump 24.100000 0.160000 24.260000 ( 26.633049)
Marshal Dump 24.440000 0.230000 24.670000 ( 27.540826)
~慢 35 倍。
如果您从该代码中删除“.to_f”,您将得到:
2.1.5
user system total real
Marshal Dump 0.160000 0.000000 0.160000 ( 0.180247)
Marshal Dump 0.180000 0.000000 0.180000 ( 0.189485)
Marshal Dump 0.160000 0.010000 0.170000 ( 0.191304)
2.2.0
user system total real
Marshal Dump 0.120000 0.010000 0.130000 ( 0.146710)
Marshal Dump 0.130000 0.010000 0.140000 ( 0.159851)
Marshal Dump 0.130000 0.000000 0.130000 ( 0.143917)
2.2.0 略微超过 2.1.5.
我有一个复杂的对象,my_object,我用它编组
Marshal.dump(my_object)
我已经在 2.1.5p273 和 2.2.0 中对调用该行 100 次的性能进行了基准测试,结果如下:
2.1.5
user system total real
Marshal Dump 7.310000 0.120000 7.430000 ( 8.988470)
Marshal Dump 7.520000 0.050000 7.570000 ( 8.210356)
Marshal Dump 7.610000 0.050000 7.660000 ( 8.432685)
2.2.0
user system total real
Marshal Dump 26.480000 0.150000 26.630000 ( 29.591742)
Marshal Dump 24.100000 0.300000 24.400000 ( 28.520397)
Marshal Dump 26.210000 0.210000 26.420000 ( 29.993412)
(我运行每个版本做3次benchmark,要彻底。)
如您所见,2.2.0 与 2.1.5 相比花费了 3 倍多的时间。我将注意力集中在 Marshal.dump 上,因为使用 ruby-prof gem,它告诉我那条线表现不佳;但我找不到获取 Marshal.dump 本身在分析器中调用的方法的方法。
编辑:经过大量实验后找到了我的答案,经过最少的复现
来源位置是nil
。
Marshal.method(:dump).source_location
#=> nil
这意味着它是一个 C 实现的方法,并且没有更多的 Ruby 代码可以跟踪。换句话说,它是一个atomic/elementary方法。
如果您认为您的结果是有效的,那么我建议您 post 将其作为 Ruby trunk 中的错误。 Ruby 的最新版本确实发现了几个性能问题,因此您的情况似乎并不罕见。
编组浮点数导致减速。
require 'benchmark'
class ToBeMarshaled
def initialize n
@a = []
n.times do |i|
@a << i.to_f
end
end
end
tbm = ToBeMarshaled.new(10000)
n = 100
Benchmark.bm do |x|
x.report("Marshal Dump") {for i in 1..n; Marshal.dump(tbm); end}
end
结果(运行 每个 Ruby 版本基准测试 3 次):
2.1.5
user system total real
Marshal Dump 0.640000 0.010000 0.650000 ( 0.744080)
Marshal Dump 0.670000 0.000000 0.670000 ( 0.758597)
Marshal Dump 0.650000 0.020000 0.670000 ( 0.747583)
2.2.0
user system total real
Marshal Dump 25.070000 0.220000 25.290000 ( 27.980023)
Marshal Dump 24.100000 0.160000 24.260000 ( 26.633049)
Marshal Dump 24.440000 0.230000 24.670000 ( 27.540826)
~慢 35 倍。
如果您从该代码中删除“.to_f”,您将得到:
2.1.5
user system total real
Marshal Dump 0.160000 0.000000 0.160000 ( 0.180247)
Marshal Dump 0.180000 0.000000 0.180000 ( 0.189485)
Marshal Dump 0.160000 0.010000 0.170000 ( 0.191304)
2.2.0
user system total real
Marshal Dump 0.120000 0.010000 0.130000 ( 0.146710)
Marshal Dump 0.130000 0.010000 0.140000 ( 0.159851)
Marshal Dump 0.130000 0.000000 0.130000 ( 0.143917)
2.2.0 略微超过 2.1.5.