Ruby 2.2.0中的编组比2.1.5慢

时间:2023-02-06 08:20:08

I have a complex object, my_object, which I marshal with

我有一个复杂的对象my_object,我将其编组

Marshal.dump(my_object)

I have benchmarked the performance of calling that line 100 times in both 2.1.5p273 and 2.2.0, and below are the results:

我已经在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)

(I ran the benchmark 3 times for each version, to be thorough.)

(我为每个版本运行了3次基准测试,要彻底。)

As you can see, it's taking in excess of 3 times as long in 2.2.0 vs 2.1.5. I zeroed in on Marshal.dump because, using the ruby-prof gem, it showed me that that was the line that was performing poorly; but I can't find a way to get the methods that Marshal.dump itself calls in the profiler.

正如你所看到的,它在2.2.0和2.1.5之间的速度超过3倍。我把它归结为Marshal.dump因为,使用ruby-prof宝石,它向我展示了那条表现不佳的线条;但我找不到一种方法来获取Marshal.dump本身在探查器中调用的方法。

Edit: see my answer with a minimal repro, found after much experimentation

编辑:经过大量实验后发现,用最小的复制品查看我的答案

2 个解决方案

#1


4  

The source location is nil.

源位置为零。

Marshal.method(:dump).source_location
#=> nil

This means that it is a C implemented method, and there is no more Ruby code that you can trace. In other words, it is an atomic/elementary method.

这意味着它是一个C实现的方法,并且没有更多的Ruby代码可以跟踪。换句话说,它是一种原子/基本方法。

If you believe your result is valid, then I suggest you to post that as a bug in Ruby trunk. Several performance issues have indeed been found for the newest versions of Ruby, so your case does not seem unusual.

如果您认为您的结果有效,那么我建议您将其作为Ruby主干中的错误发布。确实已经发现了最新版本的Ruby的几个性能问题,因此您的情况似乎并不罕见。

#2


1  

It's marshalling floats that causes the slowdown.

它是编组漂浮物导致减速。

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

results (ran benchmark 3 times for each Ruby version):

结果(每个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 times slower.

慢约35倍。

If you take the ".to_f" off of that code, you get:

如果您从该代码中取出“.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 slightly edges out 2.1.5.

2.2.0略微边缘2.1.5。

#1


4  

The source location is nil.

源位置为零。

Marshal.method(:dump).source_location
#=> nil

This means that it is a C implemented method, and there is no more Ruby code that you can trace. In other words, it is an atomic/elementary method.

这意味着它是一个C实现的方法,并且没有更多的Ruby代码可以跟踪。换句话说,它是一种原子/基本方法。

If you believe your result is valid, then I suggest you to post that as a bug in Ruby trunk. Several performance issues have indeed been found for the newest versions of Ruby, so your case does not seem unusual.

如果您认为您的结果有效,那么我建议您将其作为Ruby主干中的错误发布。确实已经发现了最新版本的Ruby的几个性能问题,因此您的情况似乎并不罕见。

#2


1  

It's marshalling floats that causes the slowdown.

它是编组漂浮物导致减速。

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

results (ran benchmark 3 times for each Ruby version):

结果(每个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 times slower.

慢约35倍。

If you take the ".to_f" off of that code, you get:

如果您从该代码中取出“.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 slightly edges out 2.1.5.

2.2.0略微边缘2.1.5。