Машалингът в Ruby 2.2.0 е по-бавен от 2.1.5

Имам сложен обект, my_object, с който маршалирам

Marshal.dump(моят_обект)

Сравних ефективността на извикване на тази линия 100 пъти както в 2.1.5p273, така и в 2.2.0, и по-долу са резултатите:

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 пъти за всяка версия, за да бъда изчерпателен.)

Както можете да видите, това отнема повече от 3 пъти повече време в 2.2.0 срещу 2.1.5. Насочих се към Marshal.dump, защото, използвайки ruby-prof gem, ми показа, че това е редът, който се представя зле; но не мога да намеря начин да получа методите, които самият Marshal.dump извиква в профайлъра.

Редактиране: вижте отговора ми с минимално повторение, намерено след много експерименти


person davej    schedule 21.01.2015    source източник
comment
За тези, които искат да следват това, сведох го до минимално повторение и го записах тук: bugs.ruby-lang.org/issues/10761. Проблемът не изглежда да е в размера, а по-скоро в сложността, тъй като трябваше да създам обект с много нива на вложени обекти в него, за да възпроизведа проблема.   -  person davej    schedule 21.01.2015
comment
Начинът, по който сте редактирали, е накарал оригиналния въпрос да изчезне и този въпрос… добре, това не е въпрос, това е основно отговор. Мисля, че всичко е интересно, но за стандартите SO мисля, че заслужава отрицателен вот.   -  person iain    schedule 21.01.2015
comment
@ian: Наистина ли? Моят избор беше да оставя въпроса, който наистина не помогна на никого, или да публикувам нещо, което според мен е доста голяма работа, или да изтрия целия въпрос. Направих това, което чувствах, че е най-добро за обществото. Честно казано, дребнавостта като вашата създава лоша репутация на маниаците.   -  person davej    schedule 21.01.2015
comment
Да наистина. Не е дребнавост, а как работи сайта. Стигнах до този въпрос и първоначалният въпрос го няма и отговорът е на негово място! Ако имате отговор, използвайте формуляр за отговор. Ако имате да правите редакции на въпроса, редактирайте го по начин, който го прави ясен. Често отнема само ред и думата Редактиране: с допълнителна информация.   -  person iain    schedule 21.01.2015
comment
Върнах го така, както беше, сега най-вече загуба на време и място, като се има предвид, че сега известната първопричина е доста специфична и първоначалната публикация вече е предимно странична. Но правилата са си правила....   -  person davej    schedule 21.01.2015
comment
Пространството в интернет е безкрайно, не се тревожете за това ;-) Гласувайте за добре оформен и интересен въпрос ^_^   -  person iain    schedule 21.01.2015
comment
Нека продължим тази дискусия в чата.   -  person davej    schedule 21.01.2015


Отговори (2)


Местоположението на източника е nil.

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

Това означава, че това е внедрен метод на C и няма повече Ruby код, който можете да проследите. С други думи, това е атомен/елементарен метод.

Ако смятате, че вашият резултат е валиден, предлагам ви да го публикувате като грешка в Рубинен ствол. Няколко проблема с производителността наистина са открити за най-новите версии на Ruby, така че вашият случай не изглежда необичаен.

person sawa    schedule 21.01.2015
comment
благодаря за техниката и предложението. Сега започва мисията за намиране на малка възпроизводима версия на проблема! - person davej; 21.01.2015

Това е маршалингът на плувки, който причинява забавянето.

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

резултати (изпълни бенчмарк 3 пъти за всяка версия на Ruby):

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.

person davej    schedule 21.01.2015