Is there a performance gain in using single quotes vs double quotes in ruby?

前端 未结 14 635
挽巷
挽巷 2020-11-27 10:32

Do you know if using double quotes instead of single quotes in ruby decreases performance in any meaningful way in ruby 1.8 and 1.9.

so if I type

qu         


        
相关标签:
14条回答
  • 2020-11-27 10:57

    It's certainly possible depending on the implementation, but the scanning portion of the interpreter should only look at each character once. It will need just an additional state (or possible set of states) and transitions to handle #{} blocks.

    In a table based scanner thats going to be a single lookup to determine transition, and will be happening for each character anyways.

    When the parser gets the scanner output, it's already known that it will have to eval code in the block. So the overhead is only really the memory overhead in the scanner/parser to handle the #{} block, which you pay for either way.

    Unless I'm missing something (or misremembering compiler construction details), which is also certainly possible :)

    0 讨论(0)
  • 2020-11-27 10:58

    No one happened to measure concatenation vs interpolation though:

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

    Specifically, note assign interp = 2.62 vs concat single = 3.76. As icing on the cake, I also find interpolation to be more readable than 'a' + var + 'b' especially with regard to spaces.

    0 讨论(0)
  • 2020-11-27 10:58

    I too thought that single quoted strings might be quicker to parse for Ruby. It doesn't seem to be the case.

    Anyway, I think the above benchmark are measuring the wrong thing, though. It stands to reason that either versions will be parsed into the same internal string representations so to get the answer as to which is quicker to parse, we shouldn't be measuring performance with string variables, but rather Ruby's speed of parsing strings.

    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
    

    Repeated runs don't seem to make much difference. It still takes pretty much the same time to parse either version of the string.

    0 讨论(0)
  • 2020-11-27 11:01

    I modded Tim Snowhite's answer.

    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
    

    Results:

    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)
    
    0 讨论(0)
  • 2020-11-27 11:05

    Thought I'd add a comparison of 1.8.7 and 1.9.2. I ran them a few times. Variance was about +-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 revision 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)
    
    0 讨论(0)
  • 2020-11-27 11:08

    I tried the following:

    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
    

    And these are the outputs:

    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
    

    If I made no mistake, it seems to me that both take approximately the same time, even though single quoted is slightly faster in most cases.

    0 讨论(0)
提交回复
热议问题