关于ruby几种String连接性能的小测试

来源:互联网 发布:九九乘法表javascript 编辑:程序博客网 时间:2024/06/05 04:41
最近开始学习Ruby. 据说“Performance”对于C++程序员来说,就像骨头对于狗一样。看到Ruby里连接String有几种不同的方式,心里面就好奇哪种最快。写了个测试程序如下:

代码:
require 'benchmark'
include Benchmark

N=100000
EMPTY=""
S="a"*1000
s=""

bm(1) do |x|
    x.report("2-1:") { N.times { S+S } }
    x.report("2-2:") { N.times { "#{S}#{S}" } }
    x.report("2-3:") { N.times { s=""; s<<S<<S } }
    x.report("2-4:") { N.times { s.replace(EMPTY); s<<S<<S } }

    x.report("3-1:") { N.times { S+S+S } }
    x.report("3-2:") { N.times { "#{S}#{S}#{S}" } }
    x.report("3-3:") { N.times { s=""; s<<S<<S<<S } }
    x.report("3-4:") { N.times { s.replace(EMPTY); s<<S<<S<<S } }

    x.report("4-1:") { N.times { S+S+S+S } }
    x.report("4-2:") { N.times { "#{S}#{S}#{S}#{S}" } }
    x.report("4-3:") { N.times { s=""; s<<S<<S<<S<<S } }
    x.report("4-4:") { N.times { s.replace(EMPTY); s<<S<<S<<S<<S } }
end
 
测试结果:
       user     system      total        real
2-1:  1.016000   0.328000   1.344000 (  1.391000)
2-2:  1.391000   0.422000   1.813000 (  1.812000)
2-3:  1.562000   0.313000   1.875000 (  1.907000)
2-4:  1.094000   0.000000   1.094000 (  1.093000)

3-1:  2.281000   1.015000   3.296000 (  3.313000)
3-2:  2.516000   0.641000   3.157000 (  3.187000)
3-3:  2.406000   0.797000   3.203000 (  3.204000)
3-4:  1.641000   0.000000   1.641000 (  1.640000)

4-1:  3.859000   1.859000   5.718000 (  5.781000)
4-2:  2.328000   0.875000   3.203000 (  3.204000)
4-3:  2.578000   0.813000   3.391000 (  3.437000)
4-4:  1.906000   0.015000   1.921000 (  1.922000)

分析:
1)S+S.....+S
      这种方式,实际是调用rb_str_plus(见Ruby源代码: string.c).而rb_str_plus作的事情主要是:
rb_str_plus(str1, str2)
  malloc memory
, length=str1.length+str2.length
  copy str1 to new memory
  copy str2 to new memory
end

   需要拷贝内存的长度:
   S+S:          2*S.length
   S+S+S:     2*(2*S.length)+S.length=5*S.length
   S+S+S+S:2*(5*S.length)+S.length=11*S.length
   ......

2)"#{S}#{S}....#{S}"
      没有找到这种方式的源代码。但是因为测试结果和第三种方式类似,实现方式也应该差不多。我猜测因为第三种方式需要“调用”方法(或者是说发送消息),因而比第二种方式稍慢一点。

3)
s=""; s<<S<<S.....<<S
     
这种方式,实际是调用rb_str_concat(见Ruby源代码: string.c).而rb_str_concat作的事情主要是:
rb_str_concat(str1, str2)
  realloc memory, length
=str1.length+str2.length+1
  copy str2 to new memory
end
  
   需要拷贝内存的长度:
   S+S:          1*S.length
   S+S+S:     2*S.length
   S+S+S+S:3*S.length
   ......

   需要注意的是:
   s="";  每次都会产生一个新的空字符串

4)
s.replace(EMPTY); s<<S<<S<<....S
      
这种方式,和第三种方式基本相同,除了:
       s.replace(EMPTY);   不会每次产生一个新的空字符串。

       有趣的是,在Ruby1.8里,String类没有clear方法。在1.9里面才有:
http://blade.nagaokaut.ac.jp/cgi-bin/scat.rb/ruby/ruby-talk/189314
  
结论:
 
1)一般而言,第四种方式最快,第一种方式最慢。
 2)避免Ruby分配过多的新String,可以较明显的提高性能。
 3)在性能不是特别重要的情况下,第二种方式最好,因为一般比第一种快,而且只需要一条语句。
原创粉丝点击