我有一个辅助方法,它执行昂贵的计算并返回Hash
,并且此Hash在我的整个应用程序生命周期内是不变的(意味着它只能在重新部署后更改)并且它也不会任何争论。
为了提高性能,我希望我可以“缓存”生成的Hash
。
我不想要为此使用Rails缓存,因为我想避免额外的memcached之旅,我不希望将字符串反序列化为哈希的开销。
我的第一个想法是将结果哈希值分配给常量并在其上调用.freeze
。但帮助器是一个实例方法,常量存在于类中,我不得不做这个超级hacky解决方案:
module FooHelper
def expensive_calculation_method
resulting_hash
end
EXPENSIVE_CALCULATION_CONSTANT = Class.new.extend(self).expensive_calculation_method.freeze
这是因为辅助方法是一个实例方法,帮助程序是一个模块(导致假类扩展所以我可以调用实例方法)而且我还必须在实例方法之后声明常量(如果我在module FooHelper
之后立即声明,我得到undefined method 'expensive_calculation_method'
。
第二个想法是使用memoization,但至少对于Rails控制器来说,memoization是变量在单个请求的生命周期中的持久性,因此只有在多次重用变量时它才有用。来自单一请求,这不是我的情况,但同时Helpers是模块,而不是要实例化的类,此时我不知道该怎么做。
我如何缓存哈希值,或以持续超过请求的方式记忆它?
答案 0 :(得分:0)
如果你想在发布时缓存一些痛苦的操作结果:
module MyExpensiveOperation
COMPUTED_RESULT = OtherModule.expensive_operation
def self.cached
COMPUTED_RESULT
end
end
确保以某种方式加载模块或不启动模块。您可以随时在require
或environment.rb
类型文件中强制使用config/initializer
该模块。
如果你想延迟加载,基本原理是一样的:
module MyExpensiveOperation
def self.cached
return @cached if (defined?(@cached))
@cached = OtherModule.expensive_operation
end
end
这将处理因任何原因返回nil
或false
的操作。它将运行一次,只运行一次,除非您有多个线程同时触发它。如果是这种情况,可以通过自动锁定方式识别模块的并发性。
答案 1 :(得分:0)
根据您的评论,这只会在应用程序启动时更改,因此将其放在初始化程序中就可以了。
# config/initializers/expensive_thing.rb
$EXENSIVE_THING_GLOBAL = expensive_calculation
# or
EXPENSIVE_THING_CONSTANT = expensive_calculation
# or
Rails.application.config.expensive_thing = expensive_calcualatioin