我读过的关于Ruby符号的每一篇文章都谈到了符号在字符串上的效率。但是,这不是20世纪70年代。我的电脑可以处理一些额外的垃圾收集。我错了吗?我有最新最好的奔腾双核处理器和4演出的RAM。我认为应该足以处理一些字符串。
答案 0 :(得分:17)
你的计算机很可能能够处理“一点点额外的垃圾收集”,但是当这个“一点点”发生在一个运行数百万次的内循环中呢?什么时候它在内存有限的嵌入式系统上运行?
有很多地方可以随便使用字符串,但有些地方你不能。这一切都取决于具体情况。
答案 1 :(得分:13)
确实,出于记忆原因,你不需要令牌非常糟糕。你的计算机无疑可以处理各种粗糙的字符串处理。
但是,除了速度更快之外,令牌还有额外的优势(尤其是上下文着色)在视觉上尖叫:看看我,我是一个关键值对的关键。这对我来说是一个很好的理由。
还有其他原因......而且很多因素的性能提升可能比你意识到的要多,特别是做比较之类的事情。
比较两个ruby符号时,解释器只是比较两个对象地址。比较两个字符串时,解释器必须一次比较一个字符。如果你做了很多这样的计算,那么这种计算就会加起来。
虽然符号有自己的性能问题但它们从不被垃圾收集。
值得一读这篇文章: http://www.randomhacks.net/articles/2007/01/20/13-ways-of-looking-at-a-ruby-symbol
答案 2 :(得分:2)
很好的是,符号保证是唯一的 - 可以有一些你不会从String中获得的好效果(例如它们的地址总是完全相同)。
另外他们有不同的含义你想在不同的领域使用它们,但是ruby对这种东西并不是太严格,所以我能理解你的问题。
答案 3 :(得分:2)
这是差异的真正原因:字符串永远不会相同。即使内容相同,字符串的每个实例都是一个单独的对象。对字符串的大多数操作都会生成 new 字符串对象。请考虑以下事项:
a = 'zowie'
b = 'zowie'
a == b #=> true
从表面上看,很容易声称a
和b
是相同的。大多数常识操作都会按照您的预期运行。但是:
a.object_id #=> 2152589920 (when I ran this in irb)
b.object_id #=> 2152572980
a.equal?(b) #=> false
他们看起来相同,但他们是不同的对象。 Ruby必须分配两次内存,两次执行String#initialize
方法,等等。它们在内存中占用两个独立的位置。嘿!当您尝试修改它们时会变得更加有趣:
a += '' #=> 'zowie'
a.object_id #=> 2151845240
这里我们将 nothing 添加到a
并保留内容完全相同 - 但Ruby不知道这一点。它仍然分配一个全新的String对象,将变量a
重新分配给它,旧的String对象坐在那里等待最终的垃圾收集。哦,空的''
字符串也会获得一个临时的String对象,该对象仅在该行代码的持续时间内分配。试试吧,看看:
''.object_id #=> 2152710260
''.object_id #=> 2152694840
''.object_id #=> 2152681980
在光滑的多千兆赫处理器上,这些对象分配是否快速?当然可以。他们会嚼掉你4 GB内存的大部分吗?不,他们不会。但这样做了几百万次,它开始加起来。大多数应用程序在整个地方使用临时字符串,并且您的代码可能在方法和循环中充满了字符串文字。每个字符串文字等都会分配一个新的String对象,每次该代码行都会运行。真正的问题甚至不是记忆浪费;这是垃圾收集过于频繁触发而你的应用程序开始挂起所浪费的时间。
相反,请看一下符号:
a = :zowie
b = :zowie
a.object_id #=> 456488
b.object_id #=> 456488
a == b #=> true
a.equal?(b) #=> true
一旦符号:zowie
生成,它就永远不会生成另一个符号。每次引用给定的符号时,都指的是同一个对象。没有时间或内存浪费在新的分配上。如果你对它们过于疯狂,这也可能是一个缺点 - 它们从不垃圾收集,所以如果你开始从用户输入动态创建无数符号,你就冒着无休止的内存泄漏的风险。但是对于代码中的简单文字,例如常量值或散列键,它们只是完美无缺。
这有帮助吗?这不是你的应用程序曾经做过什么。这是关于它做了数百万次的事情。
答案 4 :(得分:1)
要输入的字符少一个。这就是我需要将它们用于字符串以用于散列键等的所有理由。