在ruby中使用单引号与双引号是否有性能提升?

你知道如果在ruby中使用双引号而不是单引号,在ruby1.8和1.9中以任何有意义的方式降低性能。

所以如果我input

question = 'my question' 

比它快吗?

 question = "my question" 

我想ruby试图找出是否遇到双引号需要评估,并可能花费一些周期做这个。

 $ 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版本一起工作,并清理了头文件,并在更快的系统上运行基准testing。

这个答案省略了一些关键点。 特别要了解这些关于插值的其他答案,以及使用单引号和双引号时性能没有显着差异的原因。

总结:没有速度差异; 这个伟大的协作Ruby风格指南build议保持一致。 我现在使用'string'除非需要插值(指南中的选项A),喜欢它,但通常会看到更多的代码与"string"

细节:

从理论上讲,当你的代码被parsing时,它可能会有所作为,但是不仅一般你不关心parsing时间(与执行时间相比可以忽略不计),在这种情况下你将无法find显着的区别。

重要的是,什么时候执行它将是完全一样的

基准testing只显示了对Ruby如何工作的理解。 在这两种情况下,string都将被parsing为tSTRING_CONTENT (请参阅tSTRING_CONTENT 的源parse.y )。 换句话说,创build'string'"string"时,CPU将执行完全相同的操作。 完全相同的位将翻转完全相同的方式。 基准化这只会显示不显着的差异和其他因素(GC踢入等)的差异; 记住,在这种情况下不会有任何区别! 像这样的微基准是很难得到正确的。 看到我的gemfruity为此一个体面的工具。

请注意,如果插值forms为"...#{...}..."tSTRING_DBEG将其parsing为tSTRING_DBEG ,每个expression式在#{...}有一堆tSTRING_DVAR ,最后一个tSTRING_DEND 。 但是,只有在插值的情况下,这不是OP的内容。

我曾经build议你在任何地方使用双引号(以后可以更容易实际添加#{some_var} ),但是现在我使用单引号,除非我需要插值, \n等等…我喜欢它,并且略微更明确,因为不需要parsingstring来查看它是否包含任何expression式。

没有人碰巧测量连接与插值,但是:

 $ 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) 

具体来说,note assign interp = 2.62 vs concat single = 3.76 。 作为锦上添花,我还发现插值比'a' + var + 'b'更具可读性,特别是在空间方面。

没有区别 – 除非你使用#{some_var}风格的string插值。 但是,如果你真的这样做,你只会得到性能的好处。

从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) 

单引号可以比双引号稍快,因为词法分析器不必检查插值标记。 取决于实现等。请注意,这是一个分析时间成本,而不是运行时成本。

也就是说,实际的问题是,使用双引号string是否“以任何有意义的方式降低性能”,答案是决定性的“否”。 性能上的差异非常小,与任何真实的性能问题相比,性能上的差异都是微不足道的。 不要浪费你的时间。

当然,实际的插值是一个不同的故事。 'foo'几乎比"#{sleep 1; nil}foo"快1秒钟。

以为我会添加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 

ruby1.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) 

ruby1.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) 

双引号的键击次数要比单引号多一倍。 我总是匆忙。 我用单引号。 :)是的,我认为这是一个“性能增益”。 🙂

两个方向没有显着差异。 它必须是巨大的重要。

除了确定定时存在实际问题的时候,优化程序员的可维护性。

机器时间的成本非常小。 程序员编写代码的时间和维护成本是巨大的。

如果这意味着代码难以维护,那么节省几秒甚至几十分钟运行时间的优化有什么好处呢?

select一种风格,坚持下去,但不要select基于统计意义毫秒的运行时间的风格。

我也认为单引号string可能会更快地parsingRuby。 似乎并非如此。

无论如何,我认为上述基准测量错误的东西,虽然。 它的理由是,无论哪个版本将被parsing成相同的内部string表示,以便得到parsing哪一个更快的答案,我们不应该用stringvariables来衡量性能,而应该是Rubyparsingstring的速度。

 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 

反复运行似乎没有太大的区别。 parsingstring的任何版本仍然需要几乎相同的时间。

这当然可以取决于实现,但是解释器的扫描部分应该只查看每个字符一次。 它将只需要一个额外的状态(或可能的一组状态)和转换来处理#{}块。

在一个基于表格的扫描仪中,这将是一个单一的查找来确定过渡,并将发生在每个字符反正。

当parsing器获得扫描器输出时,已经知道它将不得不在块中评估代码。 所以开销只是扫描器/parsing器中用来处理#{}块的内存开销。

除非我错过了一些东西(或者错误的编译器构造细节),这当然也是可能的:)

 ~ > 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) 

有一个你都错过了

这里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和运行testing中这么做吗?

我修改了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) 

我尝试了以下内容:

 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 

如果我没有弄错的话,在我看来,两者大致是一样的,尽pipe在大多数情况下,单引号的速度稍快。