ruby字符串文字缓存?

时间:2016-08-30 19:29:45

标签: ruby string

我有这种形式的代码:

class String
  def is_jpg?
    start_with? "\xFF\xD8\xFF".b
  end
end

String#b返回字符串的副本,但编码为ASCII-8BIT。我的问题

ruby​​解释器是否足够智能以在上面的示例中缓存b()的结果,以便对不同的String实例调用此方法不必为每个创建“\ xFF \ xD8 \ xFF”的新副本时间?或者我应该做些什么:

class String
  JPG_SIGNATURE = "\xFF\xD8\xFF".b
  def is_jpg?
    start_with? JPG_SIGNATURE
  end
end

答案是否取决于ruby版本和/或解释器?我很快将MRI 2.2.x用于2.3.x。

3 个答案:

答案 0 :(得分:3)

不,默认情况下,Ruby会创建String的新副本,但您可以通过冻结String

来防止此问题
class String
  def is_jpg?
    start_with? "\xFF\xD8\xFF".freeze.b
  end
end

class String
  JPG_SIGNATURE = "\xFF\xD8\xFF".freeze.b
  def is_jpg?
    start_with? JPG_SIGNATURE
  end
end

您可以在本文中阅读有关此内容的更多信息。 http://blog.honeybadger.io/when-to-use-freeze-and-frozen-in-ruby/

答案 1 :(得分:1)

回答你的问题:

  

ruby​​解释器是否足够智能以缓存b()

的结果

没有。这与Ruby核心概念背道而驰。像这样的字符串文字每次都会被视为新对象。

def foo
  x = 'foo'
  puts x.object_id
end

> foo
70281000268840
> foo
70281000264340

您的第二种选择是更好的方法。常量应定义一次。并且它将在内存中保留单个空间。

您也可以使用String::JPG_SIGNATURE = "\xFF\xD8\xFF".b

定义相同内容

修改:阅读kcdragon's answer。他建议freeze来处理它,而基准数字真的很漂亮!

答案 2 :(得分:0)

我对三个实现进行了基准测试:普通没有优化,使用const,并使用冻结字符串。

            user     system      total        real
normal  0.270000   0.000000   0.270000 (  0.272052)
const   0.160000   0.000000   0.160000 (  0.155427)
freeze  0.240000   0.000000   0.240000 (  0.238170)

看来在使用官方Ruby VM的机器上,字符串没有被缓存,因为使用const确实可以提高速度。冻结绳子也可以提高效果但是要小得多。

请注意,为了看到任何明显的差异,我必须调用百万次方法。我会将此归类为过早优化,除非您的分析显示此特定方法是一个严重的瓶颈。