Gsub vs Tr: Продолжение
Попробуем взглянуть на вот такой код пошире. В прошлый раз мы ускорили часть этого метода в четыре раза, изменив вторую строчку следующим образом:
def base_zip_log_name_v2
t = Time.now.utc.iso8601
%(App-#{guid}-#{t.tr!(':.'.freeze, '_'.freeze)}) # <<< HERE
end
Дело в том, что это уменьшение, внезапно, производительность собственно метода увеличивает не так значительно.
def guid
'644e1dd7-2a7f-18fb-b8ed-ed78c3f92c2b'.freeze
end
def base_zip_log_name_orig
t = Time.now.utc.iso8601
# Name the file based on GUID and time. GUID and Date/time of the request are as close to unique filename as we're going to get
%(App-#{guid}-#{t}).gsub!(/:|\./, "_")
end
Benchmark.ips do |x|
x.report('before') { base_zip_log_name_orig }
x.report('after') { base_zip_log_name_v2 }
x.compare!
end
__END__
after: 66363.6 i/s
before: 42316.9 i/s - 1.57x slower
Попробуем выжать ещё немного. Посмотрим, что делает метод iso8601:
[1] pry(main)> $ Time.now.utc.iso8601
From: /Users/viktar/.rvm/rubies/ruby-2.2.3/lib/ruby/2.2.0/time.rb @ line 672:
Owner: Time
Visibility: public
Number of lines: 8
def xmlschema(fraction_digits=0)
fraction_digits = fraction_digits.to_i
s = strftime("%FT%T")
if fraction_digits > 0
s << strftime(".%#{fraction_digits}N")
end
s << (utc? ? 'Z' : strftime("%:z"))
end
По сути это strftime
с кучей ненужных нам проверок. Можно вызвать strftime
самим, убих двух зайцев сразу: выкосить ненужные проверки и избавиться от вызова tr!
. Пробуем:
def base_zip_log_name_v3
t = Time.now.utc.strftime('%FT%H_%M_%SZ'.freeze)
"App-#{guid}-#{t}"
end
Benchmark.ips do |x|
x.report('v1') { base_zip_log_name_orig }
x.report('v2') { base_zip_log_name_v2 }
x.report('v3') { base_zip_log_name_v3 }
x.compare!
end
__END__
Comparison:
v3: 93438.4 i/s
v2: 66268.1 i/s - 1.41x slower
v1: 42334.7 i/s - 2.21x slower
Ещё в полтора раза шустрее. Более чем двойное ускорение относительно оригинальной версии. Теперь запросы, которые используют этот метод, будут выполняться в среднем не 521.129ms, а 521.128ms. Ура!