Есть ли прирост производительности при использовании одинарных кавычек по сравнению с двойными в рубине? - PullRequest
122 голосов
/ 03 декабря 2009

Знаете ли вы, если использование двойных кавычек вместо одинарных кавычек в ruby ​​снижает сколько-нибудь значительную производительность в ruby ​​1.8 и 1.9.

так что если я наберу

question = 'my question'

это быстрее чем

question = "my question"

Я полагаю, что ruby ​​пытается выяснить, нужно ли что-то оценивать, когда он встречает двойные кавычки и, вероятно, тратит некоторые циклы именно на это.

Ответы [ 14 ]

103 голосов
/ 03 декабря 2009

Резюме: нет разницы в скорости; Это отличное совместное руководство по стилю Ruby рекомендует быть последовательным. Теперь я использую 'string', если не требуется интерполяция (опция A в руководстве) и мне нравится, но вы, как правило, увидите больше кода с "string".

подробности:

Теоретически, это может иметь значение, когда ваш код проанализирован , но не только если вы не заботитесь о времени анализа в целом (ничтожно мало по сравнению со временем выполнения), вы не сможете найти существенная разница в этом случае.

Важно то, что когда выполняется выполнено , оно будет точно таким же .

Сравнительный анализ показывает только отсутствие понимания того, как работает Ruby. В обоих случаях строки будут проанализированы в tSTRING_CONTENT (см. источник в parse.y). Другими словами, процессор будет выполнять те же самые операции при создании 'string' или "string". Точно такие же биты будут отображаться точно так же. Сравнительный анализ показывает только различия, которые не являются значительными и обусловлены другими факторами (включение GC и т. Д.); помните, в этом случае не может быть никакой разницы! Микро-тесты, подобные этим, получить сложно. Смотрите мой драгоценный камень fruity для достойного инструмента для этого.

Обратите внимание, что если есть интерполяция формы "...#{...}...", это будет проанализировано с tSTRING_DBEG, связкой tSTRING_DVAR для каждого выражения в #{...} и окончательным tSTRING_DEND. Это только в том случае, если есть интерполяция, но это не то, о чем говорит ОП.

Раньше я предлагал вам использовать двойные кавычки везде (это упрощает добавление этого #{some_var} позже), но теперь я использую одиночные кавычки, если мне не нужна интерполяция, \n и т. Д. Мне нравится визуально и это немного более явно, так как нет необходимости анализировать строку, чтобы увидеть, содержит ли она какое-либо выражение.

85 голосов
/ 03 декабря 2009
$ ruby -v
ruby 1.9.3p0 (2011-10-30 revision 33570) [x86_64-darwin11.0.0]

$ cat benchmark_quotes.rb
# As of Ruby 1.9 Benchmark must be required
require 'benchmark'

n = 1000000
Benchmark.bm(15) do |x|
  x.report("assign single") { n.times do; c = 'a string'; end}
  x.report("assign double") { n.times do; c = "a string"; end}
  x.report("concat single") { n.times do; 'a string ' + 'b string'; end}
  x.report("concat double") { n.times do; "a string " + "b string"; end}
end

$ ruby benchmark_quotes.rb 

                      user     system      total        real
assign single     0.110000   0.000000   0.110000 (  0.116867)
assign double     0.120000   0.000000   0.120000 (  0.116761)
concat single     0.280000   0.000000   0.280000 (  0.276964)
concat double     0.270000   0.000000   0.270000 (  0.278146)

Примечание: я обновил это, чтобы оно работало с более новыми версиями Ruby, и очистил заголовок, и запустил тест на более быстрой системе.

В этом ответе пропущены некоторые ключевые моменты. Особенно обратите внимание на эти ответы, касающиеся интерполяции и причины , при которой нет существенной разницы в производительности при использовании одинарных и двойных кавычек.

35 голосов
/ 23 января 2010

Никто не измерял конкатенацию и интерполяцию, хотя:

$ ruby -v
ruby 1.8.7 (2008-08-11 patchlevel 72) [i686-darwin9.6.2]
$ cat benchmark_quotes.rb
require 'benchmark'
n = 1000000
Benchmark.bm do |x|
  x.report("assign single") { n.times do; c = 'a string'; end}
  x.report("assign double") { n.times do; c = "a string"; end}
  x.report("assign interp") { n.times do; c = "a string #{'b string'}"; end}
  x.report("concat single") { n.times do; 'a string ' + 'b string'; end}
  x.report("concat double") { n.times do; "a string " + "b string"; end}
end

$ ruby -w benchmark_quotes.rb 
      user     system      total        real
assign single  2.600000   1.060000   3.660000 (  3.720909)
assign double  2.590000   1.050000   3.640000 (  3.675082)
assign interp  2.620000   1.050000   3.670000 (  3.704218)
concat single  3.760000   1.080000   4.840000 (  4.888394)
concat double  3.700000   1.070000   4.770000 (  4.818794)

В частности, примечание assign interp = 2.62 против concat single = 3.76. Как глазурь на торте, я также нахожу интерполяцию более удобочитаемой, чем 'a' + var + 'b', особенно в отношении пробелов.

16 голосов
/ 03 декабря 2009

Без разницы - если вы не используете #{some_var} стиль интерполяции строк. Но вы получите удар по производительности, только если действительно это сделаете.

Изменено с Пример Zetetic :

require 'benchmark'
n = 1000000
Benchmark.bm do |x|
  x.report("assign single") { n.times do; c = 'a string'; end}
  x.report("assign double") { n.times do; c = "a string"; end}
  x.report("assign interp") { n.times do; c = "a #{n} string"; end}  
  x.report("concat single") { n.times do; 'a string ' + 'b string'; end}
  x.report("concat double") { n.times do; "a string " + "b string"; end}
  x.report("concat interp") { n.times do; "a #{n} string " + "b #{n} string"; end}
end

выход

               user       system     total    real
assign single  0.370000   0.000000   0.370000 (  0.374599)
assign double  0.360000   0.000000   0.360000 (  0.366636)
assign interp  1.540000   0.010000   1.550000 (  1.577638)
concat single  1.100000   0.010000   1.110000 (  1.119720)
concat double  1.090000   0.000000   1.090000 (  1.116240)
concat interp  3.460000   0.020000   3.480000 (  3.535724)
13 голосов
/ 04 октября 2010

Одиночные кавычки могут быть немного быстрее двойных, потому что лексеру не нужно проверять #{} маркеры интерполяции. В зависимости от реализации и т. Д. Обратите внимание, что это затраты на анализ, а не на выполнение.

Тем не менее, реальный вопрос заключался в том, «уменьшает ли использование строк в двойных кавычках производительность каким-либо значимым образом», на что ответ является решающим «нет». Разница в производительности настолько невероятно мала, что она совершенно незначительна по сравнению с реальными проблемами производительности. Не трать свое время.

Фактическая интерполяция - это, конечно, другая история. 'foo' будет почти точно на 1 секунду быстрее, чем "#{sleep 1; nil}foo".

8 голосов
/ 10 ноября 2012

Двойные кавычки требуют вдвое больше ключевых нажатий, чем одинарные. Я всегда спешу. Я использую одинарные кавычки. :) И да, я считаю, что это «повышение производительности». :)

8 голосов
/ 19 октября 2010

Думаю, я бы добавил сравнение 1.8.7 и 1.9.2. Я запускал их несколько раз. Дисперсия была около + -0,01.

require 'benchmark'
n = 1000000
Benchmark.bm do |x|
  x.report("assign single") { n.times do; c = 'a string'; end}
  x.report("assign double") { n.times do; c = "a string"; end}
  x.report("assign interp") { n.times do; c = "a #{n} string"; end}
  x.report("concat single") { n.times do; 'a string ' + 'b string'; end}
  x.report("concat double") { n.times do; "a string " + "b string"; end}
  x.report("concat interp") { n.times do; "a #{n} string " + "b #{n} string"; end}
end

ruby ​​1.8.7 (2010-08-16 patchlevel 302) [x86_64-linux]

assign single  0.180000   0.000000   0.180000 (  0.187233)
assign double  0.180000   0.000000   0.180000 (  0.187566)
assign interp  0.880000   0.000000   0.880000 (  0.877584)
concat single  0.550000   0.020000   0.570000 (  0.567285)
concat double  0.570000   0.000000   0.570000 (  0.570644)
concat interp  1.800000   0.010000   1.810000 (  1.816955)

ruby ​​1.9.2p0 (2010-08-18, редакция 29036) [x86_64-linux]

  user          system      total      real
assign single  0.140000   0.000000   0.140000 (  0.144076)
assign double  0.130000   0.000000   0.130000 (  0.142316)
assign interp  0.650000   0.000000   0.650000 (  0.656088)
concat single  0.370000   0.000000   0.370000 (  0.370663)
concat double  0.370000   0.000000   0.370000 (  0.370076)
concat interp  1.420000   0.000000   1.420000 (  1.412210)
3 голосов
/ 19 октября 2010

Нет существенной разницы в обоих направлениях. Это должно быть огромно, чтобы это имело значение.

За исключением случаев, когда вы уверены, что существует реальная проблема с синхронизацией, оптимизируйте для удобства обслуживания программиста.

Стоимость машинного времени очень и очень мала. Затраты программиста на написание кода и его поддержку огромны.

Какая польза от оптимизации, позволяющей экономить секунды и даже минуты времени выполнения при тысячах запусков, если это означает, что код сложнее поддерживать?

Выберите стиль и придерживайтесь его, но не выберите этот стиль на основе статистически незначимых миллисекунд времени выполнения.

1 голос
/ 02 декабря 2013

Я тоже думал, что строки в одинарных кавычках быстрее разбираются для Ruby. Кажется, это не так.

Во всяком случае, я думаю, что приведенный выше тест измеряет не то, что нужно. Само собой разумеется, что обе версии будут разбираться в одни и те же внутренние строковые представления, поэтому, чтобы получить ответ о том, какой из них быстрее анализировать, мы должны измерять не производительность строковыми переменными, а скорость разбора строк в Ruby.

generate.rb: 
10000.times do
  ('a'..'z').to_a.each {|v| print "#{v}='This is a test string.'\n" }
end

#Generate sample ruby code with lots of strings to parse
$ ruby generate.rb > single_q.rb
#Get the double quote version
$ tr \' \" < single_q.rb > double_q.rb

#Compare execution times
$ time ruby single_q.rb 

real    0m0.978s
user    0m0.920s
sys     0m0.048s
$ time ruby double_q.rb 

real    0m0.994s
user    0m0.940s
sys     0m0.044s

Повторные прогоны, кажется, не имеют большого значения. Для анализа любой версии строки все равно требуется примерно одинаковое время.

0 голосов
/ 10 ноября 2015

Я попробовал следующее:

def measure(t)
  single_measures = []
  double_measures = []
  double_quoted_string = ""
  single_quoted_string = ''
  single_quoted = 0
  double_quoted = 0

  t.times do |i|
    t1 = Time.now
    single_quoted_string << 'a'
    t1 = Time.now - t1
    single_measures << t1

    t2 = Time.now
    double_quoted_string << "a"
    t2 = Time.now - t2
    double_measures << t2

    if t1 > t2 
      single_quoted += 1
    else
      double_quoted += 1
    end
  end
  puts "Single quoted did took longer in #{((single_quoted.to_f/t.to_f) * 100).round(2)} percent of the cases"
  puts "Double quoted did took longer in #{((double_quoted.to_f/t.to_f) * 100).round(2)} percent of the cases"

  single_measures_avg = single_measures.inject{ |sum, el| sum + el }.to_f / t
  double_measures_avg = double_measures.inject{ |sum, el| sum + el }.to_f / t
  puts "Single did took an average of #{single_measures_avg} seconds"
  puts "Double did took an average of #{double_measures_avg} seconds"
    puts "\n"
end
both = 10.times do |i|
  measure(1000000)
end

И это выходы:

1

Single quoted did took longer in 32.33 percent of the cases
Double quoted did took longer in 67.67 percent of the cases
Single did took an average of 5.032084099982639e-07 seconds
Double did took an average of 5.171539549983464e-07 seconds

2

Single quoted did took longer in 26.9 percent of the cases
Double quoted did took longer in 73.1 percent of the cases
Single did took an average of 4.998066229983696e-07 seconds
Double did took an average of 5.223457359986066e-07 seconds

3

Single quoted did took longer in 26.44 percent of the cases
Double quoted did took longer in 73.56 percent of the cases
Single did took an average of 4.97640888998877e-07 seconds
Double did took an average of 5.132918459987151e-07 seconds

4

Single quoted did took longer in 26.57 percent of the cases
Double quoted did took longer in 73.43 percent of the cases
Single did took an average of 5.017136069985988e-07 seconds
Double did took an average of 5.004514459988143e-07 seconds

5

Single quoted did took longer in 26.03 percent of the cases
Double quoted did took longer in 73.97 percent of the cases
Single did took an average of 5.059069689983285e-07 seconds
Double did took an average of 5.028807639983705e-07 seconds

6.

Single quoted did took longer in 25.78 percent of the cases
Double quoted did took longer in 74.22 percent of the cases
Single did took an average of 5.107472039991399e-07 seconds
Double did took an average of 5.216212339990241e-07 seconds

7.

Single quoted did took longer in 26.48 percent of the cases
Double quoted did took longer in 73.52 percent of the cases
Single did took an average of 5.082368429989468e-07 seconds
Double did took an average of 5.076817109989933e-07 seconds

8

Single quoted did took longer in 25.97 percent of the cases
Double quoted did took longer in 74.03 percent of the cases
Single did took an average of 5.077162969990005e-07 seconds
Double did took an average of 5.108381859991112e-07 seconds

9.

Single quoted did took longer in 26.28 percent of the cases
Double quoted did took longer in 73.72 percent of the cases
Single did took an average of 5.148080479983138e-07 seconds
Double did took an average of 5.165793929982176e-07 seconds

10

Single quoted did took longer in 25.03 percent of the cases
Double quoted did took longer in 74.97 percent of the cases
Single did took an average of 5.227828659989748e-07 seconds
Double did took an average of 5.218296609988378e-07 seconds

Если я не ошибся, мне кажется, что оба занимают примерно одно и то же время, хотя в большинстве случаев одинарные кавычки немного быстрее.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...