我有这种形式的代码:
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。
答案 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确实可以提高速度。冻结绳子也可以提高效果但是要小得多。
请注意,为了看到任何明显的差异,我必须调用百万次方法。我会将此归类为过早优化,除非您的分析显示此特定方法是一个严重的瓶颈。