Ruby Ruby 的 symbol, 感觉意义不大。。

xjz19901211 · 2014年11月16日 · 最后由 lhy20062008 回复于 2014年11月21日 · 3249 次阅读

虽然速度快了那么一点点,但却让我们陷入选择字符串还是symbol的蛋疼事中,更是出现像 Hash#stringify_keysHash#symbolize_keys这种方法,被调用者得到一个hash不得不去想一下传入的是symbol还是string。

而hash的写法也出现了{:xx => 1}{xx: 1}, 前者可以是任何对象,而后者的key就是一个symbol。。

今天闲的无聊测试了一下性能

sym_keys = []
str_keys = []
1000000.times {|i| str_keys << "number_#{i}_asdf"; sym_keys << "number_#{i}_asdf".to_sym }

require 'benchmark'

[100000, 1000000].each do |length|
  str_hash = {}; sym_hash = {}

  Benchmark.bm do |x| 
    x.report("#{length} string write") { length.times {|i| str_hash[str_keys[i]] = i } } 
    x.report("#{length} symbol write") { length.times {|i| sym_hash[sym_keys[i]] = i } } 

    x.report("#{length} string read") { length.times {|i| str_hash[str_keys[rand(length)]] } } 
    x.report("#{length} symbol read") { length.times {|i| sym_hash[sym_keys[rand(length)]] } } 
  end 
end

Ruby 2.1.3结果如下

       user     system      total        real
100000 string write  0.060000   0.000000   0.060000 (  0.064129)
100000 symbol write  0.040000   0.000000   0.040000 (  0.044240)
100000 string read  0.090000   0.000000   0.090000 (  0.098106)
100000 symbol read  0.050000   0.000000   0.050000 (  0.052136)
       user     system      total        real
1000000 string write  1.030000   0.040000   1.070000 (  1.066663)
1000000 symbol write  0.810000   0.020000   0.830000 (  0.833698)
1000000 string read  1.010000   0.010000   1.020000 (  1.021844)
1000000 symbol read  0.710000   0.000000   0.710000 (  0.713959)

从数据上看,symbol相对于string的性能提升并没有多大,而我在2.1.2下测试得到的是,在100W数据下,symbol反而变慢了,可能是symbol表太大了,查询也变慢了?这就不清楚了

抛砖引玉,大家发表下看法?我测试的只是hash, 在其它情况下是否会有更优异的表现?

写着有点离题了,我疑惑的是symbol存在的意义,现在感觉他的出现,带来的麻烦比带来的好处更多。。

共收到 15 条回复

100W的数据就可能有GC的干扰了, 牵涉到symbol的回收问题。

这些性能的差别我觉得对实际应用来说基本没有什么影响。相对于速度, 我认为使用symbol的时候更多地是表达了一种正式性,即这个key不是随意可以更改的。

至于是String还是Symbol,在Rails里面大多数情况下你都不用担心,很多都已经被ActiveSupport::HashWithIndifferentAccess处理过了。http://api.rubyonrails.org/classes/ActiveSupport/HashWithIndifferentAccess.html

至于写法,更不是问题,{:xx => 1} 与 {xx: 1} 没什么好纠结的,肯定是第二种,这个既少打几个键,也是社区通用的偏好。

@billy 是的,在rails下,大多数情况都会被自动处理,但在非rails的时候,还是需要自动来处理一下,而像写法,{xx: 1}并不能满足所有需求,不得已时,需要两种写法混用,比如key是一个变量时,非常别扭的

我觉得,更多的意义是为了让这个key不能随意更改,虽然我在使用中,还没有出现过修改一个key的情况,但确实可能出现这种情况

相对来说,我更愿意少掉一个symbol的概念,少掉一堆像symbolize_key这样的操作,统一的hash写法,自己来维护一个hash的key不被修改,因为这种情况平常基本上不会见到,有的时间自己处理一下也ok

感觉我帖子内容,写着有点离题了,我想问的是symbol存在的意义,现在感觉他的出现,带来的麻烦比带来的好处更多。。

首先有个本质的问题,字符串的比较其实是字符串对应的symbol的比较。 没有symbol的话基本上String的大部分方法都会变得奇慢无比。

symbol对应的C语言的类型是unsigned int,并且和ruby进程中的String是一一对应的,这样的话,一些比较字符串之类的处理就可以通过简单的比较整数来解决。自然unsigned int的比较要比char * 的速度快。

symbol 是 lisp 的遗留产物啦, 后来 string 的越来越优化了就逐渐没多大意义了

#5楼 @luikore 我也觉得是这样,会不会哪天 Ruby 就取消 symbol 了呢

数学里的减号, 感觉意义不大。。 关键字 unless, 感觉意义不大。。

symbol更重要的是一个概念上面的意义。symbol就是一个概念标识,而字符串就是一个需要处理的数据。没有symbol,像python一样只用string,感觉都混在一起了。

我也同样觉得,symbol 在Hash 里使用意义不大。甚至觉得Hash里就不应该允许symbol出现。

其他地方还是有意义的。

能用 symbol 的地方, 我绝对不用 string

ruby中的symbol更多是起规范意义,比如强制用snake_case(不要拿“”.to_sym说事),表示这些是特定意义的key(同名smybol对象的objet id是唯一/同一的);而string是比较随意的/变量性质的,一般用于表达式右值中。

这种测试的场合不太好,也没有多大意义,如果一个rails程序中,把代码中大量的不变的字符串都替换成symbol的话,我觉得内存消耗,性能上一定会大有不同的。

:sym'sym' 看起来爽

第一次看到:symbol这个样式,我都醉了,不晓得啥意思,头大

性能只是一个方面,在高并发多用户的情况下,sym更节省内存。

需要 登录 后方可回复, 如果你还没有账号请点击这里 注册