你知道在ruby中使用双引号而不是单引号会在ruby 1.8和1.9中以任何有意义的方式降低性能。
所以,如果我输入
question = 'my question'
比
更快question = "my question"
我认为ruby会在遇到双引号时尝试弄清楚是否需要对某些内容进行评估,并且可能花费一些周期来做这件事。
答案 0 :(得分:103)
摘要:没有速度差异;这great collaborative Ruby style guide建议保持一致。我现在使用'string'
除非需要插值(指南中的选项A)并且喜欢它,但您通常会看到更多代码"string"
。
<强>详细信息:强>
理论上,它可以在您的代码解析时产生影响,但不仅一般不关心解析时间(与执行时间相比可忽略不计),您将无法在这种情况下找到显着的差异。
重要的是,当执行时,它将完全相同。
对此进行基准测试只表明对Ruby的工作方式缺乏了解。在这两种情况下,字符串都会被解析为tSTRING_CONTENT
(请参阅the source in parse.y
)。换句话说,在创建'string'
或"string"
时,CPU将执行完全相同的操作。完全相同的位将以完全相同的方式翻转。对此进行基准测试只会显示不显着的差异以及其他因素(GC启动等);记住,在这种情况下不会有任何区别!像这样的微观基准很难做到。请参阅我的宝石fruity
以获得一个不错的工具。
请注意,如果存在"...#{...}..."
形式的插值,则会将tSTRING_DBEG
解析为tSTRING_DVAR
,#{...}
中的每个表达式的tSTRING_DEND
和{ #{some_var}
。只有在插值时才会这样,这不是OP的意思。
我曾建议你到处使用双引号(以后更容易实际添加\n
),但我现在使用单引号,除非我需要插值,{{1}}等...我在视觉上喜欢它,它稍微更明确,因为不需要解析字符串以查看它是否包含任何表达式。
答案 1 :(得分:85)
$ 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版本,并清理标题,并在更快的系统上运行基准测试。
这个答案省略了一些要点。在使用单引号和双引号时,请特别查看有关interpolation的其他答案以及原因there is no significant difference in performance。
答案 2 :(得分:35)
没有人碰巧测量连接与插值:
$ 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
vs concat single = 3.76
。
作为锦上添花,我还发现插值比'a' + var + 'b'
更具可读性,特别是在空格方面。
答案 3 :(得分:16)
没有区别 - 除非您使用#{some_var}
样式字符串插值。但是如果你真的这样做,你只能获得性能。
从Zetetic's示例修改:
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)
答案 4 :(得分:13)
单引号可能比双引号快一点,因为词法分析器不必检查#{}
插值标记。取决于实现等。请注意,这是分析时成本,而不是运行时成本。
尽管如此,实际的问题是,使用双引号字符串是否“以任何有意义的方式降低性能”,答案是决定性的“否”。性能差异非常小,与任何真正的性能问题相比,它都是微不足道的。不要浪费你的时间。
当然,实际插值是一个不同的故事。 'foo'
几乎比"#{sleep 1; nil}foo"
快1秒。
答案 5 :(得分:8)
以为我会添加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)
答案 6 :(得分:8)
双引号输入的键击次数是单引号的两倍。我总是匆忙。我用单引号。 :)是的,我认为这是“性能提升”。 :)
答案 7 :(得分:3)
两个方向都没有显着差异。重要的是它必须是巨大的。
除非您确定时序存在实际问题,否则请优化程序员的可维护性。
机器时间的成本非常小。程序员编写代码和维护代码所需的时间是巨大的。
如果这意味着代码难以维护,那么优化可以节省几秒钟,甚至几分钟的运行时间就可以节省多少?
选择一种风格并坚持下去,但不根据统计上无关紧要的毫秒运行时间选择该风格。
答案 8 :(得分:1)
我也认为单引号字符串可能更快解析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
重复运行似乎没有太大区别。解析任一版本的字符串仍然需要几乎相同的时间。
答案 9 :(得分:0)
取决于实现,这当然是可能的,但是解释器的扫描部分应该只查看每个字符一次。它只需要一个额外的状态(或一组可能的状态)和转换来处理#{}块。
在一个基于表格的扫描仪中,它将成为单个查找以确定转换,并且无论如何都将发生在每个字符上。
当解析器获得扫描仪输出时,它是已经知道它必须在块中eval代码。所以开销实际上只是扫描器/解析器中处理#{}块的内存开销,你可以用这两种方式支付。
除非我遗漏了某些东西(或错误记录编译器构造细节),这当然也是可能的:)
答案 10 :(得分:0)
~ > ruby -v
jruby 1.6.7 (ruby-1.8.7-p357) (2012-02-22 3e82bc8) (Java HotSpot(TM) 64-Bit Server VM 1.6.0_37) [darwin-x86_64-java]
~ > cat qu.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("concat single") { n.times do; 'a string ' + 'b string'; end}
x.report("concat double") { n.times do; "a string " + "b string"; end}
end
~ > ruby qu.rb
user system total real
assign single 0.186000 0.000000 0.186000 ( 0.151000)
assign double 0.062000 0.000000 0.062000 ( 0.062000)
concat single 0.156000 0.000000 0.156000 ( 0.156000)
concat double 0.124000 0.000000 0.124000 ( 0.124000)
答案 11 :(得分:0)
你们都错过了一个。
HERE doc
试试这个
require 'benchmark'
mark = <<EOS
a string
EOS
n = 1000000
Benchmark.bm do |x|
x.report("assign here doc") {n.times do; mark; end}
end
它给了我
`asign here doc 0.141000 0.000000 0.141000 ( 0.140625)`
和
'concat single quotes 1.813000 0.000000 1.813000 ( 1.843750)'
'concat double quotes 1.812000 0.000000 1.812000 ( 1.828125)'
所以它肯定比concat更好并且写下所有这些看跌期权。
我希望看到Ruby在文档操作语言的基础上进行更多的教学。
毕竟,我们不是真的在Rails,Sinatra和运行测试中这样做吗?
答案 12 :(得分:0)
我修改了Tim Snowhite的答案。
require 'benchmark'
n = 1000000
attr_accessor = :a_str_single, :b_str_single, :a_str_double, :b_str_double
@a_str_single = 'a string'
@b_str_single = 'b string'
@a_str_double = "a string"
@b_str_double = "b string"
@did_print = false
def reset!
@a_str_single = 'a string'
@b_str_single = 'b string'
@a_str_double = "a string"
@b_str_double = "b string"
end
Benchmark.bm do |x|
x.report('assign single ') { n.times do; c = 'a string'; end}
x.report('assign via << single') { c =''; n.times do; c << 'a string'; end}
x.report('assign double ') { n.times do; c = "a string"; end}
x.report('assing 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}
x.report('concat single interp') { n.times do; "#{@a_str_single}#{@b_str_single}"; end}
x.report('concat single << ') { n.times do; @a_str_single << @b_str_single; end}
reset!
# unless @did_print
# @did_print = true
# puts @a_str_single.length
# puts " a_str_single: #{@a_str_single} , b_str_single: #{@b_str_single} !!"
# end
x.report('concat double interp') { n.times do; "#{@a_str_double}#{@b_str_double}"; end}
x.report('concat double << ') { n.times do; @a_str_double << @b_str_double; end}
end
结果:
jruby 1.7.4 (1.9.3p392) 2013-05-16 2390d3b on Java HotSpot(TM) 64-Bit Server VM 1.7.0_10-b18 [darwin-x86_64]
user system total real
assign single 0.220000 0.010000 0.230000 ( 0.108000)
assign via << single 0.280000 0.010000 0.290000 ( 0.138000)
assign double 0.050000 0.000000 0.050000 ( 0.047000)
assing interp 0.100000 0.010000 0.110000 ( 0.056000)
concat single 0.230000 0.010000 0.240000 ( 0.159000)
concat double 0.150000 0.010000 0.160000 ( 0.101000)
concat single interp 0.170000 0.000000 0.170000 ( 0.121000)
concat single << 0.100000 0.000000 0.100000 ( 0.076000)
concat double interp 0.160000 0.000000 0.160000 ( 0.108000)
concat double << 0.100000 0.000000 0.100000 ( 0.074000)
ruby 1.9.3p429 (2013-05-15 revision 40747) [x86_64-darwin12.4.0]
user system total real
assign single 0.100000 0.000000 0.100000 ( 0.103326)
assign via << single 0.160000 0.000000 0.160000 ( 0.163442)
assign double 0.100000 0.000000 0.100000 ( 0.102212)
assing interp 0.110000 0.000000 0.110000 ( 0.104671)
concat single 0.240000 0.000000 0.240000 ( 0.242592)
concat double 0.250000 0.000000 0.250000 ( 0.244666)
concat single interp 0.180000 0.000000 0.180000 ( 0.182263)
concat single << 0.120000 0.000000 0.120000 ( 0.126582)
concat double interp 0.180000 0.000000 0.180000 ( 0.181035)
concat double << 0.130000 0.010000 0.140000 ( 0.128731)
答案 13 :(得分:0)
我尝试了以下内容:
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
如果我没有弄错,在我看来,两者大致相同,即使单引号在大多数情况下稍快一些。